为什么可以';我是否将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方法不“知道”(也不关心)该参数的名称可能是什么(使用nameself
,因为它只是一种约定,不是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)
。