Python中的通配符?

5 投票
5 回答
16993 浏览
提问于 2025-04-17 05:25

多年来,我注意到在我接触到的各种Python代码中,有一个叫做“通配符”的变量。我原本以为它的用法和Haskell一样:可以在需要变量的地方放一个变量,但并不真正绑定它。

我曾经在一些情况下使用过这个,比如在元组解包赋值的左边,当我不需要其中一个变量的时候。

举个例子:

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

所以今天我写了类似这样的代码:

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

也就是说,我试图把下划线这个变量绑定两次,结果收到了语法错误。我很惊讶地发现,下划线其实是一个真正的变量:

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

看起来_只是一个普通的变量名,和其他变量没有什么不同。

那么,是否有一个真正的通配符变量可以像我想的那样使用(也就是说,在元组解包赋值中可以使用多个)呢?

5 个回答

3

不,Python没有和Haskell的_相对应的东西。在Python中,_通常用来表示“丢弃”的变量,但它实际上是一个有效的变量名。正如你发现的那样,在同一个上下文中(比如在一个lambda参数列表里),你不能重复使用它。

在你给出的例子中,我会直接使用索引:

lambda tup: tup[0]

或者

lambda tup: tup[1]

虽然看起来不那么优雅,但这是比较好的做法之一。

3

其实不是这样的。Python和Haskell不一样。像map、apply、reduce和lambda这些东西在Python里算是比较次要的,虽然在itertools里有一些有趣的东西。

除非你真的需要用一行的lambda表达式,不然正确的写法应该是这样的:

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

*args这个参数让你可以使用任意数量的没有名字的参数(这些参数会以一个叫args的元组形式出现)。额外的有名字的参数会放在一个叫kwargs的字典里。

我觉得在lambda里是没法做到这一点的,但通常也没必要。函数的定义可以放在任何地方。需要注意的是,如果你把函数定义放在另一个函数(或者循环)里面,你可能会做一些有趣或者说是邪恶的事情:

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)

会输出:

>>> hello
>>> world

正如@rplnt指出的,这在循环中就不一样了:

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

for f in funcs:
    f()

会输出:

>>> world
>>> world

因为循环只有一个命名空间。

4

在Python中没有通配符变量。

我一直在劝大家不要把_当作变量名。你并不是第一个把_误认为某种特殊语法的人,所以最好不要用_作为变量名,这样可以避免混淆。如果曾经有一种“约定”是用_作为临时变量名,那这个约定其实是错误的。

造成的麻烦不仅仅是混淆。例如,_在交互式解释器和常用的gettext别名中会产生冲突。

关于lambda表达式,我建议用lambda x, *args: ...来忽略除了第一个参数以外的所有参数。在其他情况下,我会使用一些明确表示我不想用的名字,比如dummy。在使用range()的循环中,我通常会写for i in range(n),然后就不使用i了。

编辑:我刚刚注意到(通过查看其他回答)你在参数列表中使用了元组解包,所以lambda x, *args: ...并不能解决你的问题。在Python 3.x中,参数列表中的元组解包功能被移除了,因为这个特性被认为太晦涩了。最好参考mipadi的回答

撰写回答