【问题标题】:Wildcards in Python?Python中的通配符?
【发布时间】:2011-11-01 16:03:55
【问题描述】:

多年来,我注意到我遇到的各种 Python 中的“通配符”变量。我认为它像 Haskell 一样工作:允许您将变量放在形式参数中需要的位置,但不绑定它。

例如,当我不需要其中一个变量时,我在元组解包赋值的左侧使用了它。

例如:

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

所以当我今天写了类似这样的东西时:

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

I.E.我尝试绑定下划线两次,收到语法错误。我惊讶地发现 _ 确实是一个实变量:

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

看起来_ 只是一个变量名,和其他变量名一样。

根据第一个示例,我是否可以随意使用真正的通配符变量(即能够在元组解包分配中使用多个)?

【问题讨论】:

    标签: python pattern-matching tuples wildcard iterable-unpacking


    【解决方案1】:

    Python 中没有通配符变量。

    我试图劝阻人们不要使用_ 作为变量名已经有一段时间了。您不是第一个将_ 误认为某种特殊语法的人,所以最好不要将_ 用作变量名以避免这种混淆。如果曾经有使用_ 作为一次性变量名的“约定”,那么这种约定是错误的。

    除了它引起的混乱之外,还有更多的问题。例如,_ 与交互式解释器中的 _ 和常见的 gettext 别名发生冲突。

    关于lambda 表达式,我只使用lambda x, *args: ... 来忽略除第一个参数之外的所有参数。在其他情况下,我会使用明确说明我不想使用它们的名称,例如dummy。对于range()s 的循环,我通常使用for i in range(n),而根本不使用i

    编辑:我刚刚注意到(通过查看其他答案)您在参数列表中使用元组解包,因此 lambda x, *args: ... 不能解决您的问题。 Python 3.x 中删除了参数列表中的元组解包,因为它被认为是一个太晦涩的功能。最好改用mipadi's answer

    【讨论】:

      【解决方案2】:

      不是真的。 Python 不是 Haskell。 Map、apply、reduce 和 lambda 是一种二等公民,尽管在 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
      

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

      【讨论】:

      • 在 python 3 中,这也适用于解包,例如:(a, *rest, b) = [1,2,3,4]
      • 另外,循环应该不是问题,因为它们没有自己的命名空间。
      • 另外,您当然可以将*** 与lambda 一起使用。
      【解决方案3】:

      不,Python 没有任何与 Haskell 的 _ 等效的工具。 Python 中的约定是使用 _ 表示“一次性”变量,但它是一个实际的变量名称,正如您所发现的,您不能在同一上下文中使用它两次(如 lambda 参数列表)。

      在你给出的例子中,我只是使用索引:

      lambda tup: tup[0]
      

      lambda tup: tup[1]
      

      没有那么漂亮,但是更好的方法之一。

      【讨论】:

        【解决方案4】:

        这是可能的,有一个小技巧:

        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)]]
        

        给予

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

        我经常使用它,因为它使代码更优雅, Python 中 Haskells 美的一部分。

        【讨论】:

          【解决方案5】:

          简短的回答是否定的。可以遵循您现有的约定。那是

          (lambda (x, _1, _2): x)((1,2,3))
          

          【讨论】:

            猜你喜欢
            • 2017-06-17
            • 1970-01-01
            • 2012-02-27
            • 1970-01-01
            • 2013-09-03
            • 1970-01-01
            • 1970-01-01
            • 2010-11-27
            • 1970-01-01
            相关资源
            最近更新 更多