为什么我不能将self作为命名参数传递给Python中的实例方法?

时间:2010-03-14 20:38:01

标签: python methods metaprogramming language-lawyer

这有效:

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

但为什么这不起作用?

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

1 个答案:

答案 0 :(得分:6)

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

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

  

TypeError:未绑定的方法bar()必须   首先用Foo实例调用   争论(没有取而代之)

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

这个模糊的角落案例当然可以改变(使用Python 3.2补丁,如果语言变化“冻结”结束;-)使非绑定方法更加复杂:他们必须反省并保存第一个-argument在创建时的名称,并在每个调用时检查关键字参数,以防有人通过名称而不是按位置传递self。我认为这不会破坏任何现有的工作代码,它只会减慢每个现有的Python程序。如果你编写并提出一个实现这个复杂功能的补丁,并在python-dev上积极主张它反对肯定会遭到反对的风暴,你无疑会站在一个&gt;有机会通过它 - 祝你好运。

与此同时,我们其他人将继续获得im_func属性,这是一个非常微小的额外步骤,它必须是一个非常复杂的元编程大纲以保证这种变化 - 它不是完全是一个“特殊情况”,与将< - >> 命名参数的内置的命名参数调整的可怕困难相比较(并且不暴露他们的“论点名称”可以轻松地将命名参数转换为位置参数(现在 将是一个值得攻击的风车,恕我直言:在所有可调用的内容中,内置函数是元编程中最差的,因此! - 。)