Python是否真的为每个新实例创建了所有绑定方法?

时间:2015-05-21 16:02:45

标签: java python oop methods

我正在阅读Python(3.4)中的类,根据我的理解,似乎每个新对象都有自己的绑定方法实例。

class A:

    def __init__(self, name):
        self.name = name

    def foo(self):
        print(self.name)

a = A('One')
b = A('Two')

print(a.foo ==  b.foo)

此输出为False

这在我看来是浪费记忆。我认为内部a.foob.foo会在内部以某种方式指向内存中的一个函数:A.foo其中self作为类实例将被传递。

我认为这可能无法在语言中轻松实现。

每个新实例是否还包含其绑定方法的新实例?

如果是这样,这对于创建新对象的性能有何影响,或者比在其他语言中更谨慎地创建新对象的情况比如Java中的对象之间“共享”?

2 个答案:

答案 0 :(得分:15)

每次访问时都会按需绑定方法。

访问函数名称将调用descriptor protocol,函数对象上的classmethod将返回绑定方法。

绑定方法是一个围绕函数对象的瘦包装器;它存储对原始函数和实例的引用。在调用方法对象时,它又将调用传递给函数,并将实例作为第一个参数插入。

创建实例时不会创建方法,因此a-priori不需要额外的内存。

您可以手动重新创建步骤:

>>> class A:
...     def __init__(self, name):
...         self.name = name
...     def foo(self):
...         print(self.name)
... 
>>> a = A('One')
>>> a.foo
<bound method A.foo of <__main__.A object at 0x100a27978>>
>>> a.foo.__self__
<__main__.A object at 0x100a27978>
>>> a.foo.__func__
<function A.foo at 0x100a22598>
>>> A.__dict__['foo']
<function A.foo at 0x100a22598>
>>> A.__dict__['foo'].__get__(a, A)
<bound method A.foo of <__main__.A object at 0x100a27978>>
>>> A.__dict__['foo'].__get__(a, A)()
One

每次只重建方法对象;基本功能保持稳定:

>>> a.foo is a.foo
False
>>> b = A('Two')
>>> b.foo is a.foo
False
>>> b.foo.__func__ is a.foo.__func__
True

此架构还可以使staticmethodpropertyMSDN个对象正常工作。您可以创建自己的描述符,创建一系列有趣的绑定行为。

答案 1 :(得分:0)

我所做的揭密检查器显示,函数保存在主类A字典中,并在实例之间共享。但是最后几行显示了一旦我们将方法绑定在唯一的内存地址上,就可以了。

class A:

    def __init__(self, name):
        self.name = name

    def foo(self):
        print(self.name)

a = A('One')
b = A('Two')

d=a.__dict__
D=A.__dict__
print('dict a:', d)
print('dict A:', D)

print(D['foo']) #<function A.foo at 0x000001AF4258CC80>
# both next __func__ point to the parent dict
print(a.foo.__func__) #<function A.foo at 0x000001AF4258CC80>
print(b.foo.__func__) #<function A.foo at 0x000001AF4258CC80>

print(a.foo)
print(b.foo)
#already bound on unique address
print(a.foo==b.foo)

完整输出:

dict a: {'name': 'One'}
dict A: {'__module__': '__main__', '__init__': <function A.__init__ at 0x000001AF425D3730>, 'foo': <function A.foo at 0x000001AF425D3620>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
<function A.foo at 0x000001AF425D3620>
<function A.foo at 0x000001AF425D3620>
<function A.foo at 0x000001AF425D3620>
<bound method A.foo of <__main__.A object at 0x000001AF425E21D0>>
<bound method A.foo of <__main__.A object at 0x000001AF42375C50>>
False