使用元编程进行简单调试
介绍
现代调试器的“监视”功能允许开发人员查看变量何时改变状态。我在进行小型调试冲刺时经常使用此功能。不幸的是,使用监视需要打开像PyCharm这样的大型IDE。由于我更喜欢主要使用命令行和vim,因此这个过程很繁琐,似乎没有必要。
因此,我决定编写自己的调试“实用程序”来处理这种“观察”调试工作流程的非常简单的方法。
要求
- 便于使用
- 一次追踪多个属性
- 显示变量何时发生变化以及其新值
- 显示监视变量变化的堆栈跟踪/位置
属性设定
第一步是跟踪变量的设置时间。幸运的是,Python专门为此目的提供了一个__setattr__ 。每次设置属性时,都会在实际赋值之前调用__setattr__ 方法。
我在dunder 演讲中简要讨论了连接 Python 的属性设置机制,因此如果您对此类功能感兴趣,请查看该演讲。
观察特定属性
现在我们需要一个要监视的属性列表。然后,我们可以提供一个自定义的__setattr__ 方法,该方法监视每个属性“设置”操作并在发生更改时提醒我们。
def __setattr__(self, name, value):
if name in ['myvar1', 'myvar2']:
import traceback
import sys
# Print stack (without this __setattr__ call)
traceback.print_stack(sys._getframe(1))
print '%s -> %s = %s' % (repr(self), name, value)
缺点
上述方法有效,但它并没有给我们太多的灵活性。
假设我想在另一个类中使用此功能。我需要复制整个方法并修改属性列表。复制/粘贴所有代码只是为了更改一行代码,这似乎很可惜。一定有更好的方法。
可重用性的步骤
我们可以对提出的解决方案更加批判性地看待,并注意以下几点:
- 该解决方案将属性列表和实际的实现细节紧密结合在一起。
- 我们将始终重写相同的方法,__setattr__。
- 该方法必须始终存在于类内部才能起作用。
我们需要一种方法将属性名称列表传递给类方法,该方法将监视这些属性的__setattr__操作。更具体地说,我们希望以通用方式覆盖内置类方法,并将要监视的属性列表作为其唯一参数传递。
潜在的解决方案
这听起来像是类装饰器的绝佳用法。这是一个完美的用例,因为所需的唯一信息是要监视的属性列表。此外,使用装饰器可以让我们使用@装饰器语法将此行为添加到任何类中。
因此,事不宜迟:
def watch_variables(var_list):
"""Usage: @watch_variables(['myvar1', 'myvar2'])"""
def _decorator(cos):
def _setattr(self, name, value):
if name in var_list:
import traceback
import sys
# Print stack (without this __setattr__ call)
traceback.print_stack(sys._getframe(1))
print '%s -> %s = %s' % (repr(self), name, value)
return super(cls, self).__setattr__(name, value)
cls.__setattr__ = _setattr
return cos
return _decorator
简而言之,我们创建自己的_setattr方法,然后将装饰类的__setattr__设置为我们的新版本。要监视属性,我们只需使用类上方的@watch_variables装饰器并传入属性名称列表。例如:
@watch_variables(['foo', 'bar'])
class BuggyClass(object):
def __init__(self, foo, bar):
self.foo = foo
self.bar = bar
结论
上述解决方案在我最近的调试冲刺中起作用,并且应该在许多标准情况下起作用。
不幸的是,这个解决方案有一个主要缺点:它无法跟踪可变属性的变化。例如,如果您的类具有通过附加或其他一些变异修改的列表属性,此装饰器不会提醒您,因为append()方法和其他相关的列表修改机制是操作列表属性的方法,而不是我们的类。因此,我们自定义的__setattr__版本永远不会被调用。
我确信可以将此功能添加到我们现有的项目中。作为对读者的练习,展示您的技能并分叉我的解决方案以“修复”此缺陷或指出更好的解决方案!
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~