自我如何在Python中受到约束?

Jer*_*emy 2 python self

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

aba*_*ert 5

有关完整详细信息,请参阅此博客文章.但我可以在这里总结一下.

关键是要理解绑定方法.绑定方法只是一个对象,它包含实际的函数对象及其绑定的实例.像这样的东西:

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)