Python 默认参数的函数

4 投票
3 回答
1516 浏览
提问于 2025-04-16 19:13

我该如何在方法里访问 qux 呢?我真的需要在 foo() 的内部重新定义它吗,还是有办法从 self 导入它?

class Baz(object):

    qux = lambda x : x + '_quux'

    def foo(self, bar=qux('fred')):
        print bar

        print qux('waldo')
        # NameError: global name 'qux' is not defined

        print Baz.qux('waldo')
        # TypeError: unbound method <lambda>() must be called with Baz instance as first argument (got str instance instead)

        print Baz.qux(self, 'waldo')
        # TypeError: <lambda>() takes exactly 1 argument (2 given)

        print self.qux('waldo')
        # TypeError: <lambda>() takes exactly 1 argument (2 given)                

3 个回答

1

一种解决办法是使用

qux = staticmethod(lambda x : x + '_quux')

然后这样访问它

Baz.qux('waldo')

我建议把它移出这个类。

7

如果你想从类中访问某个方法,那么你必须使用 classmethodstaticmethod

class Baz(object):
  qux = staticmethod(lambda x : x + '_quux')

但是 不要这样做

1

qux 被当作实例方法来处理,因为这是类成员看起来像函数时的默认处理方式(更具体地说,当你通过一个实例查找 Baz.qux 时,会隐式调用 __get__ 来将第一个参数绑定到实例上)。但是,你没有在开头提供 self 参数。因此,baz 被绑定到了 x 这个 lambda 参数上。

在 Python 中,'self' 这个名字并没有什么神奇之处;它只是一个约定。 方法绑定总是通过绑定到函数的第一个参数来工作的。

如果你聪明的话,可以自己验证这一点:

class Baz(object):
    qux = lambda x: x + '_quux'
    def foo(self): return self.qux()

Baz().foo() # TypeError: unsupported operand type(s) for +: 'Baz' and 'str'
# because after binding Baz() to 'x', we get Baz() + '_quux'

一个解决方案是明确将 qux 设为 staticmethod,就像 Sven Marnach 的回答中提到的那样。(你也可以将它设为 classmethod,这是 Python 特有的概念,更加强大;staticmethod 的行为更接近于 Java 中的 static 关键字。)注意,和 Java 一样,你也可以在 foo 中通过 self.qux 来访问 staticmethod。这通过用 staticmethod 安装的新机制替换了函数的正常 __get__ 机制来实现。

另一个解决方案是在 lambda 参数中提供 self 参数。如果你实际上不想要“静态”行为(也就是说,确实需要做一些与 self 相关的事情)——但看起来你确实想要。为了完整性,这样写会是:

qux = lambda self, x: x + '_quux'
def foo(self):
    return self.qux('foo')

撰写回答