Python方法对象创建

标签 python python-3.x python-internals

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

让我们以这个类为例

class Foo:

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

让我们创建一个类实例

fooInstance = Foo()

当我阅读文档并亲自测试时,我意识到 每次我在代码中引用或每次我从实例调用 bar 时

fooInstance.bar

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

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

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

抱歉,如果这个问题“愚蠢”,我对Python完全陌生,所以我对它的了解很少,甚至更少了解它的内部结构。

最佳答案

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 。我们可以用它来生成绑定(bind)方法:

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

事实上,当您访问作为函数的类的属性时,Python 会自动为您执行此操作。

现在,讨论缓存问题——函数可以从任何地方放入类中。我可以像上面那样向任何类添加绑定(bind)方法 - 简单地分配 b.fn = fn.__get__(b, Bar) ,现在实例 b 具有绑定(bind)方法 fn,即使 Bar 的其他实例都没有该方法。我可以为多个类(class)执行此操作。如果描述符要缓存值,则需要保留一个查找表来查找实例和类,以查看它是否已经为该实例和类创建了绑定(bind)方法。这是一个更简单的示例:

def fn(self):
    return self

class A(object):
    fn = fn

class B(object):
    fn = fn

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

查找表的构建首先存在问题,因为 self 可能不可散列。我认为这可能是每次创建新实例的主要原因。 即使情况并非如此,查找表也需要存储弱引用(而不是实际引用),以便在必要时可以对整个内容进行垃圾收集。 我猜测创建一个新的绑定(bind)方法可能几乎与使用弱引用时进行查找和解析一样快。

关于Python方法对象创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25537069/

相关文章:

python - pandas 重新采样应用 np.average

python-3.x - Python - 如何递归搜索作为列表元素的文本中的变量子字符串

python - 通过对列数据的按位操作(位掩码)过滤结构化数组

python - 使用 subprocess.check_output() 在 python 中搜索文件

python - 如何使用 Python 2 和 Python 3 中的内置库 ElementTree 等实体解析 HTML?

python - 在 Python 中找到最低值并从多个列表中弹出

python - 提交按钮在 python 3 中无法正常工作。怎么解决?

内置 "in"算子的Python源码

python - 为什么 Python 的语法规范不包括文档字符串和注释?

python - obj.__closure__ 中究竟包含什么?