如何使装饰器对调试器透明

How to make a decorator transparent to debugger

我正在开发一个装饰器库,它正在修改一个函数的关键字参数,并且该库正在做我想要它做的事情,但是在调试时非常不方便,每当调用用户函数时,调试器必须通过装饰器库代码。

我将装饰器实现为 class(参见 https://github.com/mapa17/configfy/blob/master/configfy/decorator.py

并且用户函数由以下库代码包装:

def __call__(self, *args, **kwargs):
    if self.needs_wrapping:
        self.needs_wrapping = False
        self.func = args[0]
        functools.update_wrapper(self, self.func)
        self.kwargs = self.__get_kw_args(self.func)

        # If config file is specified in decorator, new kwargs can be precalculated!
        if self.config is not None:
            self.new_kwargs = self._get_new_kwargs()

        return self

    # Use precalculated kwargs if available
    if self.new_kwargs is None:
        new_kwargs = self._get_new_kwargs()
    else:
        new_kwargs = self.new_kwargs

    # Overwrite them with any passed arguments; passed arguments have priority!
    new_kwargs.update(kwargs)

    # Call target (aka user) function with altered kwargs
    return self.func(*args, **new_kwargs)

那么在调试时是否可以以某种方式跳过这个库代码?

装饰器没什么神奇的。 @decorator 语法只是语法糖,所以当你写:

@decorate
def some_func(...):
   # ...

技术上真正发生的是:

def some_func(...):
   # ...

some_func = decorate(some_func)

IOW,不,没有办法 "make a decorator transparent to the debugger",因为 "decorator" 只是一个普通的普通可调用对象(通常但不一定)returns 另一个普通的普通可调用对象 -事实上,根本就没有 "decorator" 这样的东西,如果你这样使用,可调用对象就是装饰器,仅此而已。

如@bruno-desthuilliers 所述,装饰器是用户函数的包装器,无法以某种方式删除它。

可以做的是,使用 skip 选项让调试器跳过装饰器模块代码 see

因为我对使用 pudb 进行调试很感兴趣,所以我创建了一个拉取请求,为 pdb 启用了类似的功能 see

对于 pdb

import pdb
from configfy import configfy as cfy    

@cfy
def fuu(kw_me=42):
    print(kw_me)

if __name__ == '__main__':
    pdb.Pdb(skip=['configfy.*']).set_trace()
    fuu()

对于 pudb(如果拉取请求被接受)

import pudb
from configfy import configfy as cfy

# Prevent pudb from stepping into the decorator library code
pudb._get_debugger(skip=['configfy.*'])


@cfy
def fuu(kw_me=42):
    print(kw_me)

if __name__ == '__main__':
    pudb.set_trace()
    fuu()