【问题标题】:Why can't I pass self as a named argument to an instance method in Python?为什么我不能将 self 作为命名参数传递给 Python 中的实例方法?
【发布时间】:2010-03-14 20:38:01
【问题描述】:

这行得通:

>>> def bar(x, y):
...     print x, y
...
>>> bar(y=3, x=1)
1 3

这很有效:

>>> class Foo(object):
...     def bar(self, x, y):
...             print x, y
...
>>> z = Foo()
>>> z.bar(y=3, x=1)
1 3

即使这样也有效:

>>> Foo.bar(z, y=3, x=1)
1 3

但是为什么这在 Python 2.x 中不起作用?

>>> Foo.bar(self=z, y=3, x=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)

这使得元编程更加困难,因为它需要特殊情况处理。我很好奇它是 Python 的语义所必需的还是只是实现的工件。

【问题讨论】:

  • 类名应大写,即class Foo(object)

标签: python methods language-lawyer metaprogramming python-2.x


【解决方案1】:

z.bar 是一个绑定 方法——它已经有一个im_self 属性,它成为底层函数对象的第一个参数(通常命名为self),绑定方法的@987654324 @ 属性。要覆盖它,您显然需要重新绑定 im_selfedit: 或改为调用 im_func)——无论您在参数传递方面做什么都不会对其产生任何影响, 当然。是的,这就是 记录的绑定方法对象在 Python 中的工作方式(不仅仅是实现细节:每个正确的 Python 实现都必须以这种方式完成)。所以它是“必要的”,因为它是使 Python 成为它的语言的一部分,而不是一种略有不同或强烈不同的语言。当然你可以设计一种不同的语言来选择完全不同的规则,但是——当然不会是 Python。

编辑:OP 的编辑澄清了他正在调用 unbound 方法,而不是绑定方法。这仍然不起作用,从尝试得到的错误消息中可以清楚地看到原因:

TypeError:未绑定的方法 bar() 必须 首先调用 Foo 实例 争论(一无所获)

这个非常明确的错误消息背后的规则是实例必须是第一个参数(所以当然是位置参数:命名参数没有顺序)。未绑定的方法不“知道”(也不关心)该参数的 name 可能是什么(并且使用名称 self 只是一个 约定,不是 Python 语言的规则):它只关心“第一个参数”的明确条件(当然是位置参数)。

这个晦涩的极端情况当然可以通过使未绑定的方法变得更加复杂来改变(使用 Python 3.2 补丁,如果并且当语言更改“冻结”结束时;-):他们必须自省并保存第一个-创建时参数的名称,并在每次调用时检查关键字参数,以防有人通过名称而不是位置传递self。我认为这不会破坏任何现有的工作代码,它只会减慢几乎所有现有的 Python 程序。如果你编写并提出一个补丁来实现这个复杂性,并在 python-dev 上积极支持它来反对势在必行的反对风暴,你毫无疑问会有 > 0 的机会通过它——祝你好运.

与此同时,我们其他人将继续获得im_func 属性,作为一个荒谬的微小额外步骤,必须是一个相当复杂的元编程的独立大厦才能保证这样的改变——它不是与将命名参数传递给不采用命名参数(并且不暴露它们的“参数名称”,以便轻松地将命名参数转换为位置参数(现在将是一个值得攻击的风车,恕我直言:在所有可调用对象中,内置函数是最糟糕的元编程,正因为如此!- )。

【讨论】:

  • foo 是类,所以foo.bar 是一个未绑定的方法,不是吗?
  • 据我了解, foo.bar 不是绑定方法,因为 foo 是一个类,而不是一个实例。 foo.bar 有一个 im_self 属性,但它的值为 None。
  • @Mike: z.bar() 没有被调用; Foo.bar() 是。问题是为什么不为 self works 指定一个 kwarg,而指定它失败了。
  • @Alex:我不确定我是否认同你所说的“它只会减慢几乎所有现有的 Python 程序”——查看 Objects/classobject.c 中的 instancemethod_call(),它看起来对我来说,您可以在不影响主代码路径的情况下进行必要的更改。也就是说,我仍然同意你的观点,这可能不值得做。 :)
  • 请注意,没有什么可以为 Python 3.2(或任何更高的 Python 3 版本)打补丁,因为未绑定的方法已经像 Python 3 中的 Dodo 一样(应得的)。不再有未绑定的方法,而是返回未包装的原始函数对象,您可以将 self 参数的关键字参数用于您的心脏内容。
猜你喜欢
  • 2022-01-05
  • 1970-01-01
  • 2021-03-12
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
  • 2015-02-28
  • 2020-01-26
  • 1970-01-01
相关资源
最近更新 更多