【问题标题】:Get access to kwargs and args at the wrapper of decorator在装饰器的包装器中访问 kwargs 和 args
【发布时间】:2019-02-11 16:15:31
【问题描述】:

我有一个基于类的装饰器。问题是我需要能够访问包装函数 args 和 kwargs 但现在我不能而且我不明白为什么。这应该很容易,但不适合我。

class limit:
    def __call__(self, fn):
        @wraps(fn)
        # the idea to use signature like (request, *args, **kwargs) is bad. I must accept *args and **kwargs only 
        def wrapper(*args, **kwargs):
             # pdb breakpoint is here
             user = kwargs.get('user') or kwargs.get('request').user // ERROR

             return fn(*args, **kwargs)

        return wrapper

让我们看看pdb。那是****审查****疯了。

(Pdb) args
args = (<User: dua>,)
kwargs = {}
(Pdb) kwargs
{}
(Pdb) args.args
args = (<User: dua>,)
kwargs = {}
(Pdb) args.args.args.args
args = (<User: dua>,)
kwargs = {}
(Pdb) args.get('user')
args = (<User: dua>,)
kwargs = {}
(Pdb) type(args)
<class 'tuple'>
(Pdb) 

问题是如何访问 args、kwargs 并将 args 视为列表,将 kwargs 视为 dict。

附:我不知道为什么它 args 和 kwargs 看起来像那样。为什么它们看起来像那样?


正如答案args 中提到的,是pdb 的命令。用户repr(args) 查看参数。

下一个问题是可能的函数签名: 1) def fn(请求, ...) 2) def fn(self, a, b, c, etc, user) 3) 定义 fn(用户)

有没有办法用一个装饰器来处理所有这些问题?


【问题讨论】:

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


    【解决方案1】:

    您的pdb 输出并不真正相关,args 在这里的作用类似于交互式 pdb 命令。

    为了简单起见,要么使用repr(args) 要么临时重命名*args 参数

    【讨论】:

    • 感谢您的帮助!我可以让 wrapper 只接受 **kwargs(不要使用 *args)吗?我必须有权访问参数,但装饰函数的签名可以更改。这就是为什么我需要 params 作为字典。
    • 你可以,但通常这是个坏主意,因为装饰器的想法——你事先不知道函数签名。即使在您的调试会话中,您的修饰函数也会将 User 作为位置参数传递
    • 有没有办法将位置参数传递给 kwargs dict?因为def wrapper(**kwargs): 给出错误(尝试传递位置参数但失败)。
    • 没有明确的方法可以做到这一点。一旦你尝试实现它假设你可以,你就会明白为什么。如果调用者传递位置参数,你怎么能通过kwargs 访问它?他们没有名字
    • @Slam 可以检查函数的签名以获取位置参数的名称。对于未在其签名中提供参数名称的函数,这将失败。
    【解决方案2】:

    我最终得到了这个解决方案:

    def wrapper(*args, **kwargs):
        user = None
        fn_signature_args = inspect.getfullargspec(fn).args
        # looking for a user in kwargs
        if 'user' in kwargs:
        user = kwargs['user']
        # looking for a user as positional argument
        elif 'user' in fn_signature_args:
        index = fn_signature_args.index('user')
        user = args[index]
        # looking for a user as self or request attribute
        elif fn_signature_args[0] in ('request', 'self'):
        user = args[0].user
    

    【讨论】:

      猜你喜欢
      • 2018-08-28
      • 2013-09-25
      • 1970-01-01
      • 2016-04-20
      • 2014-04-26
      • 1970-01-01
      • 2011-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多