<p>首先,有一个警告:函数调用很少会限制您的速度。这通常是不必要的微观优化。只有这样做,如果它是真正限制你的表现。在之前做一些好的分析,看看是否有更好的方法来优化。</p>
<p><strong>确保您不会为这个小小的性能调整牺牲易读性!</strong></p>
<p>Python中的类有点难理解。</p>
<p>它的工作方式是每个对象都有一个<code>__dict__</code>字段(dict),其中包含该对象包含的所有属性。此外,每个对象都有一个<code>__class__</code>对象,该对象再次包含一个<code>__dict__</code>字段(同样是dict),该字段包含所有类属性。</p>
<p>例如,看看这个:</p>
<pre><code>>>> class X(): # I know this is an old-style class declaration, but this causes far less clutter for this demonstration
... def y(self):
... pass
...
>>> x = X()
>>> x.__class__.__dict__
{'y': <function y at 0x6ffffe29938>, '__module__': '__main__', '__doc__': None}
</code></pre>
<p>如果动态定义函数(因此不是在类声明中而是在对象创建之后),则函数不会转到<code>x.__class__.__dict__</code>,而是转到<code>x.__dict__</code>。</p>
<p>还有两个dict保存了当前函数中可访问的所有变量。这里有<code>globals()</code>和<code>locals()</code>,其中包括所有全局和局部变量。</p>
<p>现在我们假设有一个类<code>x</code>的对象<code>X</code>,它的函数<code>y</code>和<code>z</code>是在类声明中声明的,第二个函数<code>z</code>是动态定义的。假设对象<code>x</code>是在全局空间中定义的。
此外,为了进行比较,还有两个函数<code>flocal()</code>,在局部空间中定义,和<code>fglobal()</code>,在全局空间中定义。</p>
<p>现在我将展示如果您调用这些函数中的每一个:</p>
<pre><code>flocal():
locals()["flocal"]()
fglobal():
locals()["fglobal"] -> not found
globals()["fglobal"]()
x.y():
locals()["x"] -> not found
globals()["x"].__dict__["y"] -> not found, because y is in class space
.__class__.__dict__["y"]()
x.z():
locals()["x"] -> not found
globals()["x"].__dict__["z"]() -> found in object dict, ignoring z() in class space
</code></pre>
<p>如您所见,类空间方法需要更多的时间来查找,对象空间方法也很慢。最快的选择是本地函数。</p>
<p>但你可以在不牺牲课程的情况下绕过它。比如说,x.y()被频繁调用,需要优化。</p>
<pre><code>class X():
def y(self):
pass
x = X()
for i in range(100000):
x.y() # slow
y = x.y # move the function lookup outside of loop
for i in range(100000):
y() # faster
</code></pre>
<p>类似的事情发生在对象的成员变量上。它们也比局部变量慢。如果调用函数或使用对象中的成员变量(该对象是其他对象的成员变量)时,效果也会增加。例如</p>
<pre><code>a.b.c.d.e.f()
</code></pre>
<p>会比较慢,因为每个点都需要另一个字典查找。</p>
<p>正式的Python性能指南建议避免代码的性能关键部分出现点:
<a href="https://wiki.python.org/moin/PythonSpeed/PerformanceTips" rel="noreferrer">https://wiki.python.org/moin/PythonSpeed/PerformanceTips</a></p>