Python inspect.getmembers 与装饰器一起使用时未返回实际函数

6 投票
2 回答
2723 浏览
提问于 2025-04-17 12:44

我有三个Python函数:

def decorator_function(func)
  def wrapper(..)
    return func(*args, **kwargs)
  return wrapper

def plain_func(...)

@decorator_func
def wrapped_func(....)

它们在一个叫做模块A的地方。

现在我想获取这个模块A里面的所有函数,所以我这样做:

for fname, func in inspect.getmembers(A, inspect.isfunction):
  # My code

这里的问题是,func的值并不是我想要的。

我希望得到的是decorator_function、plain_func和wrapped_func,而不是wrapper。

我该怎么做才能确保返回的是wrapped_func,而不是wrapper呢?

2 个回答

6

你可以通过以下方式访问已经装饰过的函数:

wrapped_func.func_closure[0].cell_contents()

举个例子,

def decorator_function(func):
  def wrapper(*args, **kwargs):
      print('Bar')
      return func(*args, **kwargs)
  return wrapper   

@decorator_function
def wrapped_func():
    print('Foo')

wrapped_func.func_closure[0].cell_contents()

会打印出

Foo    # Note, `Bar` was not also printed

不过其实,如果你知道自己想要访问那个已经装饰过的函数,那么定义起来会简单很多,

def wrapped_func():
    print('Foo')

deco_wrapped_func = decorator_function(wrapped_func)

所以 wrapped_func 就是那个已经装饰过的函数,而 deco_wrapped_func 则是装饰后的版本。

5

如果你只是想让外部能看到原来的函数名字,我觉得你可以这样做:

@functools.wraps

把它作为你的装饰器的装饰器

下面是标准文档中的一个例子:

>>> from functools import wraps
>>> def my_decorator(f):
...     @wraps(f)
...     def wrapper(*args, **kwds):
...         print('Calling decorated function')
...         return f(*args, **kwds)
...     return wrapper
...
>>> @my_decorator
... def example():
...     """Docstring"""
...     print('Called example function')
...
>>> example()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'

撰写回答