为什么可以';我是否将self作为命名参数传递给Python中的实例方法?

为什么可以';我是否将self作为命名参数传递给Python中的实例方法?,python,methods,language-lawyer,metaprogramming,python-2.x,Python,Methods,Language Lawyer,Metaprogramming,Python 2.x,这项工作: >>> 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 >>>

这项工作:

>>> 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
这是有效的:

>>> 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
即使这样也行得通:

>>> 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
但是为什么这在Python2.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)
Foo.bar(self=z,y=3,x=1) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 TypeError:必须使用Foo实例作为第一个参数调用unbound方法bar()(但没有得到任何结果) 这使得元编程更加困难,因为它需要特殊的案例处理。我很好奇这是Python的语义所必需的,还是仅仅是实现的产物。

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

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

TypeError:未绑定的方法栏()必须 以Foo实例作为第一个实例调用 争论(什么都没有得到)

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

通过使未绑定的方法变得更加复杂,这个晦涩难懂的情况当然可以改变(使用Python 3.2补丁,如果语言更改“冻结”结束;-),它们必须在创建时反思并保存第一个参数的名称,并检查每个调用的关键字参数,以防有人按姓名而不是位置传递
self
。我不认为这会破坏任何现有的工作代码,它只会降低几乎所有现有Python程序的速度。如果您编写并提出一个实现这一复杂问题的补丁,并在python开发中积极支持它,以对抗必然会到来的反对浪潮,那么毫无疑问,您将有>0的机会来实现它——祝您好运


与此同时,我们其余的人将继续使用
im_func
属性,这是一个非常复杂的元编程体系中的一个非常小的额外步骤,可以保证这样的改变——这根本不是“特例”,与将命名参数传递到不接受命名参数(并且不公开其“参数名称”以方便将命名参数转换为位置参数)的内置对象相比,将命名参数传递到具有可怕的困难(现在这将是一个值得攻击的风车,IMHO:在所有可调用函数中,内置函数是元编程最糟糕的,正因为如此!).

foo
是类,所以
foo.bar
是一个未绑定的方法,不是吗?据我所知,foo.bar不是一个绑定的方法,因为foo是一个类,不是一个实例。foo.bar有一个im_self属性,但它的值是None。@Mike:
z.bar()
没有被调用;
foo.bar()
是。问题是为什么不为self works指定kwarg,而指定kwarg会失败。@Alex:我不确定我是否同意你的说法,即“它只会降低几乎所有现有Python程序的速度”——看看instancemethod_call()在Objects/classobject.c中,我认为您可以在不影响主代码路径的情况下进行必要的更改。也就是说,我仍然同意您的看法,这可能不值得这么做。:)请注意,对于Python 3.2(或任何更高版本的Python 3),没有什么需要修补的,因为未绑定的方法已经过时了(活该)Python 3中的Dodo方式。不再有未绑定的方法,而是返回未包装的原始函数对象,您可以在内容中使用
self
参数的关键字参数。类名应大写,即
Class Foo(object)