【问题标题】:Get the names of a Python function’s parameters when it is inside a decorator在装饰器中获取 Python 函数参数的名称
【发布时间】:2020-03-29 12:09:54
【问题描述】:

我想在装饰器函数中获取函数的参数名称,我不断获取装饰器内部的函数包装器参数,而不是原始方法的参数

_component_name_does_not_exist_error 是装饰器,create_queue_to_component 是方法, 我想至少获得名称 component_name 和 queue_name

def _component_name_does_not_exist_error(func):
    def function_wrapper(self, component_name):
        if not self._does_component_exist(component_name):
            return self._create_response(
                False,
                f"Component named {component_name} doesn't exist"
            )
        return func

    return function_wrapper

@_component_name_does_not_exist_error
def create_queue_to_component(self, component_name,
                              queue_name, queue_size=1):
    if self.components[component_name].does_queue_exist(queue_name):
        return self._create_response(
            False,
            f"Queue named {queue_name} already exist"
        )

    self.components[component_name].create_queue(queue_name=queue_name,
                                                 queue_size=queue_size)
    return self._create_response(
        True,
        f"The Queue {queue_name} has been created"
    )

我尝试使用这些方法没有运气,都返回没有 queue_name 的 component_name (为了让下面的代码更清楚,pipeline_manager 是包含方法的类的对象)

def get_method_parameters(self):
    print(inspect.signature(self.pipeline_manager.create_queue_to_component))
    print(self.pipeline_manager.create_queue_to_component.__code__.co_varnames)
    print(inspect.getfullargspec(self.pipeline_manager.create_queue_to_component))

感谢您阅读本文并提供帮助:)

【问题讨论】:

  • 什么时候需要这些参数?您可以将它们放在装饰器内部,但不能放在外部,因为该函数已替换为包装器(并且只有参数 component_name)。

标签: python python-3.x dynamic python-decorators


【解决方案1】:

使用functools模块中的functools.wraps

import functools

def _component_name_does_not_exist_error(func):
    @functools.wraps(func)
    def function_wrapper(self, component_name):
        if not self._does_component_exist(component_name):
            return self._create_response(
                False,
                f"Component named {component_name} doesn't exist"
            )
        return func

    return function_wrapper

然后

print(inspect.signature(self.pipeline_manager.create_queue_to_component))

给你我认为你想要的,即create_queue_to_component 函数的参数名称。

This answer 很好地描述了functools.wraps

【讨论】:

  • 谢谢你的回答,你是对的,我确实得到了正确的参数名称,但是当我试图执行该方法时,我得到一个错误 TypeError: function_wrapper() 需要 2 个位置参数,但 4 个是给定
  • def function_wrapper(component_name, *args)。添加*args 允许修饰函数具有其他参数
  • 我将其更改为 def function_wrapper(self, component_name, *args, **kwargs) 并且它有效,但不适用于所有情况。在参数的第三个索引处具有其 component_name 参数的另一个函数上使用此装饰器将导致大问题。如果您有解决问题的想法,那就太好了。
  • 你能把component_name作为关键字参数传递吗?
【解决方案2】:
def _component_name_does_not_exist_error(func):
    @functools.wraps(func)
    def function_wrapper(self, *args, **kwargs):
        if not self._does_component_exist(kwargs['component_name']):
            return self._create_response(
                False,
                f"Component named {kwargs['component_name']} doesn't exist"
            )
        return func(self, *args, **kwargs)

    return function_wrapper

这对我有用 (感谢@wstk 提出您的答案并帮助我找到答案)

【讨论】:

    猜你喜欢
    • 2019-11-20
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    • 2020-12-18
    • 2010-11-03
    • 2018-10-25
    • 1970-01-01
    相关资源
    最近更新 更多