5

这有效:

>>> 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的语义是否有必要或只是实现的工件。

4

1 回答 1

6

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

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

TypeError: unbound method bar() must be called with Foo 实例作为第一个参数(什么都没有)

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

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

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

于 2010-03-14T20:43:29.190 回答