调试时如何检测实例数据属性更改?

时间:2015-10-13 13:46:15

标签: python debugging monkeypatching

我正在尝试调试使用第三方软件包的多线程程序。

在某些时候,对象的一个​​属性(不是由我直接创建)会被更改,我无法弄清楚是什么改变了它。我在代码中找不到任何改变它的东西。

由于这是第三方软件包,我不想直接更改其代码,而是根据需要从外部修改代码。

我的计划是以某种方式点击或包装设置属性的代码并设置断点或从那里打印堆栈跟踪。

我尝试了猴子修补实例的__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)

然后所有属性都在类本身上设置,因为方法绑定到它。

使用代理包装类也没有任何帮助,因为我自己并没有实例化它,而是在创建它之后的某个时刻获取实例。

如果重要,那么该类是由另一个第三方软件包创建的 ws4py WebSocket,但我认为这是一般调试技术的练习。

是否有更多“pythonic”方式利用现有实例的突变? (hack-ish方式也将受到赞赏)

1 个答案:

答案 0 :(得分:0)

我最终为班级创建了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__代替使用setattr(self, name, value) 魔法属性:

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 附加到实例而不是类,或尝试附加绑定方法:

<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>