self
在对象上调用函数时,Python如何绑定?我试图理解为什么这样:
class A(object):
def __init__(self):
self.name = 'class A'
def show_name(self):
print(self, self.name)
class B(object):
def __init__(self, a):
self.name = 'class B'
self.show_name = a.show_name
A().show_name()
B(A()).show_name()
Run Code Online (Sandbox Code Playgroud)
输出
(<self.A object at 0x7f9d35a06e50>, 'class A')
(<self.A object at 0x7f9d35a06e50>, 'class A')
Run Code Online (Sandbox Code Playgroud)
编辑:如何知道show_name
应该将类的实例A
作为其first(self
)参数,而不是类的实例B
?
有关完整详细信息,请参阅此博客文章.但我可以在这里总结一下.
关键是要理解绑定方法.绑定方法只是一个对象,它包含实际的函数对象及其绑定的实例.像这样的东西:
class BoundMethod(object):
def __init__(self, function, instance):
self.__func__ = function
self.__self__ = instance
def __call__(self, *args, **kwargs):
return self.__func__(self.__self__, *args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
绑定方法是第一类对象,因此您可以传递它们并检查它们:
>>> class C:
... def foo(self):
... print(self)
>>> C.foo
<function __main__.foo>
>>> c = C()
>>> c.foo
<bound method C.foo of <__main__.C object at 0x10ab90a90>>
>>> c.foo.__func__
<function __main__.foo>
>>> c.foo.__func__ is C.foo, c.foo.__self__ is c
(True, True)
Run Code Online (Sandbox Code Playgroud)
你甚至可以手动构建它们:
>>> import types
>>> f = types.MethodType(C.foo, 2)
>>> f
<bound method int.foo of 2>
>>> f()
2
Run Code Online (Sandbox Code Playgroud)
(虽然我上面的Python类显然不是真正的代码,但它并不遥远;如果你做了一些愚蠢的事情,比如尝试绑定绑定方法或不可调用,你甚至会得到大部分相同的错误.)
那么,c.foo
最终如何约束c
?要真正理解这一点,您需要了解描述符.但是短版是这样的:
几乎Python中的每个类型都有一个额外的方法__get__
.这用于属性访问.基本上,当你键入时c.foo
,它会做这样的事情(忽略基类,槽,getattr覆盖等):
try:
return c.__dict__['foo']
except KeyError:
value = type(c).__dict__['foo']
try:
return value.__get__(c)
except AttributeError:
return value
Run Code Online (Sandbox Code Playgroud)
__get__
函数对象上的方法返回绑定方法(绑定到其参数).
所以,回到你的例子,显然B(A()).show_name()
打印出关于A
因为B(A()).show_name
绑定到A
实例的东西......但是这是怎么发生的?
好吧,让我们来看看:
>>> a = A()
>>> b = B(a)
>>> b.show_name
Run Code Online (Sandbox Code Playgroud)
在你的__init__
功能中,你这样做:
self.show_name = a.show_name
Run Code Online (Sandbox Code Playgroud)
这只是将已经绑定的方法复制a.show_name
到普通的实例变量self.show_name
.所以,当你以后查找时b.show_name
,它是绑定的绑定方法a
.如果你想重新绑定它,你必须手动完成它,例如:
self.show_name = types.MethodType(a.show_name.__func__, self)
Run Code Online (Sandbox Code Playgroud)