Wildcards in Python?

14,573

Solution 1

There is no wildcard variable in Python.

I try to dissuade people from using _ as a variable name for quite some time now. You are not the first person mistaking _ as some kind of special syntax, so it's better not to use _ as a variable name at all to avoid this kind of confusion. If there ever was a "convention" to use _ as a throw-away variable name, this convention was misguided.

There are more problems than just the confusion it causes. For example, _ clashes with _ in the interactive interpreter and the common gettext alias.

Regarding the lambda expression, I'd just use lambda x, *args: ... to ignore all arguments except for the first one. In other cases, I'd use names explicitly stating I don't want to use them, like dummy. In case of loops of range()s, I usually use for i in range(n) and simply don't use i.

Edit: I just noticed (by looking at the other answers) that you use tuple unpacking in the argument list, so lambda x, *args: ... doesn't solve your problem. Tuple unpacking in parameter lists has been removed in Python 3.x because it was considered too obscure a feature. Better go with mipadi's answer instead.

Solution 2

No, Python doesn't have any equivalent to Haskell's _. The convention in Python is to use _ for "throwaway" variables, but it's an actual variable name, and as you found, you can't use it twice in the same context (like a lambda parameter list).

In the examples you gave, I'd just use indexing:

lambda tup: tup[0]

or

lambda tup: tup[1]

Not as pretty, but one of the better ways to do it.

Solution 3

Not really. Python is not Haskell. Map, apply, reduce, and lambda are kind of second-class citizens, though there is some interesting stuff in itertools.

Unless you have some need to use one-line lambdas, the correct way is this:

def f(x, *args, **kwargs):
    return x

The *args argument lets you use any number of unnamed arguments (which will be available as a tuple called args). Extra named arguments will be in a dictionary called kwargs.

I don't think there's any way to do this in a lambda, but there's usually no need. A function declaration can go anywhere. Note, you do interesting / evil stuff if you put the function definition inside another function (or loop):

def make_func(s):
    def f(*trash, **more_trash):
        print s
    return f

f1 = make_func('hello')
f2 = make_func('world')
f1(1,2,'ham','spam')
f2(1,2,a=1,b=2)

will output:

>>> hello
>>> world

As @rplnt pointed out, this won't be the same for loops:

funcs = []
for s in ('hello','world'):
    def f():
        print s
    funcs.append(f)

for f in funcs:
    f()

will output:

>>> world
>>> world

because loops only have one namespace.

Solution 4

It is possible, with a little trick:

class _: 
    def __eq__(x,y): return true
_=_() #always create a new _ instance if used, the class name itself is not needed anymore

[(a,b) for (a,_,_,b) in [(1,2,3,4),(5,6,7,8)]]

gives

[(1, 4), (5, 8)] 

I'm using it often, because it makes code more elegant, a part of Haskells beauty in Python.

Solution 5

Short answer is no. Could just follow your existing convention. That is

(lambda (x, _1, _2): x)((1,2,3))
Share:
14,573
Joe
Author by

Joe

I work at Crossref. Interested in Java, Clojure, Rust these days.

Updated on June 04, 2022

Comments

  • Joe
    Joe almost 2 years

    Over the years I have noticed the 'wildcard' variable in various bits and pieces of Python I've come across. I assumed it worked like Haskell: allowing you to put a variable where one was required in the formal parameters, but not binding it.

    I've used this on, for example, the left hand side of an tuple-unpacking assignment when I don't need one of the variables.

    For example:

    _, extension = os.path.splitext(filename)
    

    So when I wrote something similar to this today:

    (lambda (x,_,_): x)((1,2,3))
    

    I.E. I tried to bind the underscore twice, I received a syntax error. I was surprised to see that _ is indeed a real variable:

    (lambda (x,_,z): _)((1,2,3))
    > 2
    

    Looks like _ is just a variable name like any other.

    Is there a bona fide wildcard variable that I can use as I would like (i.e. able to use more than one in a tuple unpacking assignment), as per the first example?