2014-08-27 138 views
2

Python的类实例对象具有属性。这些属性可以是数据属性或方法。创建Python方法对象

让我们例如此类

class Foo: 

    def bar(self): 
     print("FooBar") 

并让创建一个类的实例

fooInstance = Foo() 

正如我已经从文档读取和自己测试我意识到 ,每次我在代码中引用或每次我给我打电话吧

fooInstance.bar 

每次在内部创建一个方法对象。

问题是为什么没有被缓存和重用

一个假设是因为该方法的对象的可调用对象可以以某种方式改变内部地址(即由于重新分配?)和指针它可以失效。

对不起,如果这个问题是“愚蠢的”,我对Python完全陌生,所以我的知识很少,甚至更少的内部。

回答

2

Python函数是descriptors。您可以通过简单地看它的dir检查:

>>> def fn(self): 
...  pass 
... 
>>> dir(fn) 
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name'] 
>>> fn.__get__ 
<method-wrapper '__get__' of function object at 0x7fa5585550c8> 

通知的__get__ method。我们可以用它来生成绑定方法:

>>> class Bar(object): pass 
... 
>>> b = Bar() 
>>> fn.__get__(b, Bar) 
<bound method Bar.fn of <__main__.Bar object at 0x7fa5585cdcd0>> 

其实,这是蟒蛇会自动为你做,当你在一个类,这是一个函数访问的属性。

现在,关于缓存的问题 - 函数可以放在任何地方的类上。我可以像上面那样向任何类添加绑定方法 - 简单分配b.fn = fn.__get__(b, Bar),现在实例b具有绑定方法fn,即使Bar的其他实例没有该方法。我可以为多个班级做这个。如果描述符要缓存这些值,则需要保留一个查找表,查找实例和类以查看它是否已经为该实例和类创建了绑定方法。这里有一个简单的例子:

def fn(self): 
    return self 

class A(object): 
    fn = fn 

class B(object): 
    fn = fn 

注意AB持有相同的函数的引用 - 并在必要时属性上的实例访问他们都会产生绑定方法。

由于self可能不是可破解的,所以查找表首先构建起来会产生问题。我认为这可能是每次创建新实例的主要原因。 即使不是这种情况,查找表将需要存储弱引用 - 而不是实际的引用 - 这样整个事情可以在必要时被垃圾收集。 我猜创建一个新的绑定方法可能与使用weakrefs进行查找和解析时一样快。

0

你在那里有一个方法,每次调用它将执行的方法时都没有参数。方法变量会将该方法分配给其他方法以便稍后调用它。

如果你有一个带有计数器的变量,并且每次你可以打印出来并且看看它是如何被修改的,你在该方法中增加了一个。