调试时如何检测实例数据属性的变化?

2024-06-02 08:09:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图调试一个使用第三方软件包的多线程程序。在

在某个时候,一个对象的属性(不是我直接创建的)发生了变化,我不知道是什么改变了它。我在我的代码中找不到任何改变它的东西。在

由于这是一个第三方软件包,我不希望直接更改它的代码,而是根据需要从外部进行修补。在

我的计划是以某种方式切入或包装设置属性的代码,并从中设置断点或打印堆栈跟踪。在

我尝试monkey修补实例的__setattr__方法,但没有触发。在

我还试图修补类本身:

def patch_class(target):

    def method(self, name, value):
        print(name, value)
        print("called from", target)
        setattr(self, name, value) # break or print trace here

    target.__setattr__ = types.MethodType(method, target)

patch_class(WebSocket)

但是所有的属性都是在类本身上设置的,因为方法是绑定到类上的。在

用代理来包装类也没有真正的帮助,因为我不是自己实例化它,而是在实例创建后的某个时刻获取它。在

如果重要的话,所说的类是由另一个第三方包创建的ws4pyWebSocket,但我认为这是一般调试技术中的一个练习。在

有没有一种更“Python式”的方式来挖掘现有实例的突变?我会感激你的


Tags: 实例方法代码nameselftarget属性value
1条回答
网友
1楼 · 发布于 2024-06-02 08:09:04

最后我为这个类创建了一个__setattr__。在

def setter_fun(self, name, value):
    print('setting', name, value)
    self.__dict__[name] = value
    if name is 'problematic_prop' and value is 'problematicValue':
        traceback.print_stack()

# and set the class setter magic method
instance.__class__.__setattr__ = setter_fun

也可以使用setattr而不是使用__dict__魔法属性:

^{pr2}$

现在,当某个东西将实例的problematic_prop设置为problematicValue,堆栈跟踪将被打印:

>>> class A(object):
        def __init__(self):
            self.foo = 1

        def set_problematic(self):
            self.problematic_prop = 'problematicValue'
>>> a = A()
>>> a.__class__.__setattr__ = setter_fun
>>> a.foo = 2
setting foo 2
>>> print(a.foo)
2
>>> a.set_problematic()
setting problematic_prop problematicValue
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 6, in set_problematic
  File "<input>", line 5, in setter_fun
NameError: name 'traceback' is not defined

我失败的尝试包括尝试将__setattr__附加到实例而不是类,或者尝试附加一个绑定方法:

class MyClass(object):
    def setter_fun(self, name, value):
        print('setting', name, value)
        self.__dict__[name] = value
        if name is 'problematic_prop' and value is 'problematicValue':
            traceback.print_stack()

    def set_my_function(self):
        # won't work, the function is bound to the current instance (self)
        some.instace.__class__.__setattr__ = self.setter_fun

相关问题 更多 >