【问题标题】:Python capture method call and parametersPython捕获方法调用和参数
【发布时间】:2012-12-07 04:07:17
【问题描述】:

我正在尝试从单例类捕获函数调用而不覆盖该方法。

目前我正在这样做:

class MyClass
    oldMethod = None

    def __init__(self):
        c = Class.Instance()
        self.oldMethod = c.Method #make a copy to the pointer of the original function
        c.Method = self.NewMethod #redirect it

    def NewMethod(self, x, a):
        self.oldMethod(x, a) #call the old function
        #My Stuff

我正在尝试捕获“事件”(作为方法调用)和此方法调用的参数。有没有其他方法可以说“被动”捕获它,只需听并获取参数。

注意:我无权访问单例类的代码。

谢谢

【问题讨论】:

  • 感谢您的链接,这听起来不像我想要的。我不想自己调用'Class'的方法,我想监听它何时获取并获取调用时使用的参数,而不创建'Class'的子类,因为'Class'已经创建。
  • 这正是该代码的作用。包装类调用被包装的实例并打印出参数。
  • 那么我错过了,因为代码调用了我不想做的'w.getval()'。 UI 操作调用我的方法,因此我试图从该操作中捕获回调。

标签: python


【解决方案1】:

您提到您希望在正常操作期间拦截方法调用,而不仅仅是在调试期间。该解决方案与其他答案不同,它使用Proxy pattern 方法创建一个新对象,该对象将成为对原始对象的所有调用的一种包装器。在代理级别,您可以根据需要记录和监控调用。

person.py

为了演示代码,我在person 模块中创建了一个名为Person 的示例类。我们可以假设这是您无法修改代码的模块。

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

example.py

在下面的代码中,我们创建了一个名为ProxyPerson 的代理对象,当使用它而不是Person 时,它的行为与其相同,并且具有记录所有对 greet 方法的调用的附加行为。您注意到它使用了*args, **kwargs,因此 Person 将来可能会有不同的签名,但如果进行更改,代码不会中断。

import person

class ProxyPerson(person.Person):
    def greet(self, *args, **kwargs):
        print '--- greet() self=%r args=%r kwargs=%r' % (self, args, kwargs)
        super(ProxyPerson, self).greet(*args, **kwargs)

#person.Person = ProxyPerson #uncomment to monkey patch Person

jack, jill = person.Person('Jack'), ProxyPerson('Jill')
for p in jack, jill:
    p.greet()
    p.greet('hi')
    p.greet(greeting='why hello')

常规输出

下面的输出显示了使用原始 Person 类或使用 ProxyPerson 时的执行差异。这些示例还包括不带位置参数、带位置参数和最后带关键字参数的调用。

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

猴子补丁输出

终于可以Monkey patchperson.Person类指向ProxyPerson。您可以通过注释掉example.py 中的猴子补丁行来试验这种方法。这种情况下的输出如下:

--- 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

猴子补丁的好处是所有未来的 person.Person 实例实际上都是已创建的代理对象的实例。 Monkey patching 有它自己的一系列问题,在使用它之前你应该记住这些问题。

【讨论】:

    【解决方案2】:

    您可以使用winpdb,它是一个非常易于使用的python 图形调试器。所以你只需打开有问题的python脚本,在你想看的任何类的任何方法上设置一个breakpoint。它将在此时暂停并向您显示变量的状态以及每次调用该方法时未显示的内容。

    【讨论】:

    • 您好,我希望在正常操作期间而不是在调试期间拦截函数调用。谢谢你的想法!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-06
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多