<p>您提到要在正常操作期间拦截方法调用,而不仅仅是在调试期间。这个解决方案与另一种方法不同,它使用<a href="http://en.wikipedia.org/wiki/Proxy_pattern" rel="nofollow">Proxy pattern</a>方法来生成一个新对象,该对象将作为对原始对象的所有调用的包装器。在代理级别,您可以根据需要记录和监视调用。在</p>
<p><strong>人.py</strong></p>
<p>为了演示代码,我在<code>person</code>模块中创建了一个名为<code>Person</code>的示例类。我们可以假设这是你不能修改代码的模块。在</p>
<pre><code>class Person(object):
def __init__(self, name=None):
self.name = name
def greet(self, greeting='hello'):
print '%s %s' % (greeting, self.name)
def __repr__(self):
return "Person(%r)" % self.name
</code></pre>
<p><strong>示例.py</strong></p>
<p>在下面的代码中,我们创建了一个名为<code>ProxyPerson</code>的代理对象,当使用它而不是{<cd1>}时,它的行为与它相同,并且添加了记录对greet方法的所有调用的行为。您注意到它使用了<code>*args, **kwargs</code>,因此Person将来可能会有不同的签名,但是如果进行了更改,代码不会中断。在</p>
^{pr2}$
<p><strong>常规输出</strong></p>
<p>下面的输出显示了使用原始Person类或使用ProxyPerson时的执行差异。这些示例还包括没有位置参数的调用、带有位置参数的调用,最后还有关键字参数的调用。在</p>
<pre><code>hello Jack
hi Jack
why hello Jack
- greet() self=Person('Jill') args=() kwargs={}
hello Jill
- greet() self=Person('Jill') args=('hi',) kwargs={}
hi Jill
- greet() self=Person('Jill') args=() kwargs={'greeting': 'why hello'}
why hello Jill
</code></pre>
<p><strong>猴子补丁输出</strong></p>
<p>最后,可以<a href="http://en.wikipedia.org/wiki/Monkey_patch" rel="nofollow">Monkey patch</a><code>person.Person</code>类指向ProxyPerson。您可以通过注释掉<code>example.py</code>中的monkey patch行来试验这种方法。这种情况下的输出如下:</p>
<pre><code> - greet() self=Person('Jack') args=() kwargs={}
hello Jack
- greet() self=Person('Jack') args=('hi',) kwargs={}
hi Jack
- greet() self=Person('Jack') args=() kwargs={'greeting': 'why hello'}
why hello Jack
- greet() self=Person('Jill') args=() kwargs={}
hello Jill
- greet() self=Person('Jill') args=('hi',) kwargs={}
hi Jill
- greet() self=Person('Jill') args=() kwargs={'greeting': 'why hello'}
why hello Jill
</code></pre>
<p>猴子修补的好处是人。人实际上是已创建的代理对象的实例。Monkey-patching自带一系列问题,您在使用它之前应该记住这些问题。在</p>