<p>您看到了错误的<code>calls</code>属性。下面是发生的情况:</p>
<ul>
<li><p><code>countt</code>生成一个<code>wrapper()</code>函数来替换修饰函数。我们称之为<code>countt.<local>.wrapper()</code>(即使<code>functools.wraps()</code>将<code>__name__</code>属性设置为<code>f3</code>)。这将包装原始函数<code>fn</code>,并且<code>functools.wraps()</code>将所有函数属性复制到<code>countt.<local>.wrapper()</code>。您向<code>countt.<local>.wrapper()</code>添加了一个<code>calls</code>属性,因此我们称之为<code>countt.<local>.wrapper.calls</code>。</p></li>
<li><p><code>memorize</code>生成一个<code>wrapper()</code>函数来替换修饰函数<code>fn</code>。我们称之为<code>memorize.<local>.wrapper()</code>。这将封装传入的函数<code>fn</code>,这里是<code>countt.<local>.wrapper()</code>。<code>functools.wraps()</code>将所有函数属性复制到<code>memorize.<local>.wrapper()</code>,<em>包括<code>countt.<local>.wrapper.calls</code></em>,变成<code>memorize.<local>.wrapper.calls</code>,设置为<code>0</code>。您向<code>memorize.<local>.wrapper()</code>添加了一个<code>calls2</code>属性,因此我们称之为<code>memorize.<local>.wrapper.calls2</code>。</p></li>
</ul>
<p>然后运行代码。<code>countt.<local>.wrapper()</code>不断更新<code>countt.<local>.wrapper.calls</code>。注意,<code>memorize.<local>.wrapper.calls</code>在这里从未改变过,这是一个不同的独立属性。你知道吗</p>
<p>然后打印<code>f3.calls</code>和<code>f3.calls2</code>。<code>f3.calls</code>是0,因为这实际上是<code>memorize.<local>.wrapper.calls</code>,而不是<code>countt.<local>.wrapper.calls</code>。你知道吗</p>
<p>如果运行的是Python3.2或更新版本,则可以使用<code>__wrapped__</code>属性来访问wrapped函数;<code>f3.__wrapped__</code>这里是<code>countt.<local>.wrapper()</code>,因此可以使用以下属性查看<em>正确的</em><code>calls</code>属性:</p>
<pre><code>print(f3.__wrapped__.calls)
</code></pre>