<p>Python函数是<a href="https://docs.python.org/2/howto/descriptor.html" rel="nofollow">descriptors</a>。您可以通过查看<code>dir</code>来检查这一点:</p>
<pre><code>>>> 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>
</code></pre>
<p>注意<a href="https://docs.python.org/2/howto/descriptor.html#invoking-descriptors" rel="nofollow">^{<cd2>} method</a>。我们可以使用它来生成绑定方法:</p>
<pre><code>>>> class Bar(object): pass
...
>>> b = Bar()
>>> fn.__get__(b, Bar)
<bound method Bar.fn of <__main__.Bar object at 0x7fa5585cdcd0>>
</code></pre>
<p>事实上,这就是python在访问作为函数的类的属性时自动为您做的事情。你知道吗</p>
<p>现在,关于缓存函数的问题,可以从任何地方将其放到类中。我可以向任何类添加绑定方法,就像我在上面所做的简单赋值<code>b.fn = fn.__get__(b, Bar)</code>,现在实例<code>b</code>有一个绑定方法<code>fn</code>,即使<code>Bar</code>的其他实例都没有该方法。我可以为多个班级做这个。如果描述符要缓存这些值,则需要保留一个查找实例和类的查找表,以查看是否已经为该实例和类创建了绑定方法。下面是一个简单的例子:</p>
<pre><code>def fn(self):
return self
class A(object):
fn = fn
class B(object):
fn = fn
</code></pre>
<p>注意,<code>A</code>和<code>B</code>持有对同一函数的引用,当在实例上访问该属性时,它们都会根据需要生成绑定方法。你知道吗</p>
<p>首先构造查找表是有问题的,因为<code>self</code>可能不可散列。我认为这可能是每次创建新实例的主要原因。<em>即使</em>不是这样,查找表也需要存储weakrefs而不是实际引用,以便在必要时可以对整个内容进行垃圾收集。<em>我猜</em>在使用weakrefs时,创建一个新的绑定方法可能几乎和执行查找和解析一样快。你知道吗</p>