Python方法对象创建

时间:2014-08-27 21:17:08

标签: python python-3.x python-internals

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

让我们以此类为例

class Foo:

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

然后创建一个类实例

fooInstance = Foo()

正如我从文档中读到的并经过我自己的测试,我意识到了 每次我在代码中引用或每次从实例调用bar时

fooInstance.bar

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

我的问题是为什么它不被缓存和重用

我的一个假设是因为方法对象的可调用对象可能以某种方式在内部更改地址(即由于重新分配?),并且指向它的指针可能无效。

很抱歉,如果这个问题是"愚蠢",我对Python完全不熟悉,所以我对它的了解很少,更不用说它的内部。

2 个答案:

答案 0 :(得分: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>>

实际上,当你访问一个函数类的属性时,这就是python自动为你做的事情。

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

def fn(self):
    return self

class A(object):
    fn = fn

class B(object):
    fn = fn

请注意AB包含对同一函数的引用 - 并且当在实例上访问该属性时,它们都会根据需要生成绑定方法。

查找表首先构造是有问题的,因为self可能不是可散列的。我认为这可能是每次创建新实例的主要原因。 即使不是这种情况,查找表也需要存储weakrefs - 而不是实际引用 - 以便在必要时可以对整个事物进行垃圾回收。 我猜测创建一个新的绑定方法可能与使用weakrefs时查找和解析一样快。

答案 1 :(得分:0)

每次调用它将执行的方法时,你所拥有的所有方法都没有参数。方法变量将该方法分配给其他东西以便稍后调用它。

如果您有一个带计数器的变量,并且每次打印出来时都会向该方法添加一个变量,并查看它是如何被修改的。