【问题标题】:Check if a function uses a specific keyword argument检查函数是否使用特定的关键字参数
【发布时间】:2015-10-16 19:52:24
【问题描述】:

我有一个这样的装饰器:

def auth(func):
    def dec(self, *args):
        user = Auth.auth(self.server.parse_params(), self.server.client_address)
        // snip...
        if user is None:
            raise NoSuchUserError
        func(self, *args, user=user)
    return dec

效果很好,现在我可以编写如下函数:

@auth
def serve_account(self, user=None):
    return json.dumps(user)

但有时我的函数实际上根本不读取user 参数,我只想让装饰器处理未经身份验证的用户。以此为例:

@auth
def serve_status(self, user=None):
    // I get the status here but I don't use the user parameter.
    return json.dumps(status)

现在我的 IDE 和我的静态代码分析服务一直在唠叨它:

未使用的参数“用户”

这也可能使不知道装饰器中发生了什么的人感到困惑:

TypeError: serve_status() got an unexpected keyword argument 'user'

我不能删除参数,否则一旦函数被装饰器调用,我会得到一个运行时错误。

如果函数在参数列表中没有参数,有什么方法可以省略装饰器中的参数? (除了创建第二个装饰器,如@auth_but_dont_pass_the_user

【问题讨论】:

  • “我不使用用户参数”是指您没有在函数体或其他任何地方使用它吗?
  • @AshwiniChaudhary 是的,这正是我想说的。

标签: python function arguments python-decorators


【解决方案1】:

为什么不使用**kwargs?一个例子是这样的:

def f(*args, **kwargs):
    if 'user' in kwargs:
        print 'the given user is:', kwargs['user']
    else:
        # do something else

这样您不必显式地将参数放入装饰器中,但如果用户指定它,您就可以检索它。

【讨论】:

  • 嗯,我可以这样做,但是这样看起来不是更令人困惑吗?
  • @JohannBauer:不,这是真正的标准 python,当您想要允许可选参数时建议使用。检查here
【解决方案2】:

您可以解析到被调用函数的源代码并检查user 变量被使用了多少次,如果它大于1,那么您可以使用变量user 调用该函数:

import ast
import inspect


def is_variable_used(func, variable):
    source = inspect.getsource(func).split('\n', 1)[1]  # Split to drop the decorator part
    return sum(node.id == variable for node in ast.walk(ast.parse(source))
               if isinstance(node, ast.Name)) > 1


def auth(func):
    def dec(self, *args):
        if is_variable_used(func, 'user'):
            print 'Calling {func_name} with user.'.format(func_name=func.__name__)
            return func(self, user=100)
        else:
            print 'Calling {func_name} without user.'.format(func_name=func.__name__)
            return func(self)
    return dec


@auth
def func1_with_user(foo, user=None):
    return 10 + user

@auth
def func2_with_user(foo, user=None):
    a = 10 + foo
    b = a + foo
    c = a + b + user
    return a + b + c

@auth
def func1_without_user(foo, user=None):
    pass

@auth
def func2_without_user(foo, user=None):
    return 10 + foo


print func1_with_user(10)
print func2_with_user(20)
print func1_without_user(100)
print func2_without_user(200)

输出:

>>> !python so.py
Calling func1_with_user with user.
110
Calling func2_with_user with user.
260
Calling func1_without_user without user.
None
Calling func2_without_user without user.
210

【讨论】:

    猜你喜欢
    • 2018-01-29
    • 1970-01-01
    • 2020-09-02
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 2019-05-13
    • 2022-01-05
    • 2020-10-14
    相关资源
    最近更新 更多