检查函数是否使用特定的关键字参数
Check if a function uses a specific keyword argument
我有这样的装饰器:
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 和我的静态代码分析服务一直在唠叨:
Unused argument 'user'
这也可能会让不知道装饰器中发生了什么的人感到困惑:
TypeError: serve_status() got an unexpected keyword argument 'user'
我不能删除参数,否则一旦函数被装饰器调用我就会得到一个运行时错误。
如果函数的参数列表中没有参数,有什么方法可以省略装饰器中的参数吗? (除了创建第二个装饰器,如 @auth_but_dont_pass_the_user
)
为什么不使用 **kwargs
?一个例子是这样的:
def f(*args, **kwargs):
if 'user' in kwargs:
print 'the given user is:', kwargs['user']
else:
# do something else
这样您就不必显式地将参数放入装饰器中,但如果用户指定它,您就可以检索它。
您可以解析到被调用函数的来源并检查 user
变量被使用了多少次,如果它大于 1 那么您可以使用变量 [=12= 调用该函数]:
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
我有这样的装饰器:
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 和我的静态代码分析服务一直在唠叨:
Unused argument 'user'
这也可能会让不知道装饰器中发生了什么的人感到困惑:
TypeError: serve_status() got an unexpected keyword argument 'user'
我不能删除参数,否则一旦函数被装饰器调用我就会得到一个运行时错误。
如果函数的参数列表中没有参数,有什么方法可以省略装饰器中的参数吗? (除了创建第二个装饰器,如 @auth_but_dont_pass_the_user
)
为什么不使用 **kwargs
?一个例子是这样的:
def f(*args, **kwargs):
if 'user' in kwargs:
print 'the given user is:', kwargs['user']
else:
# do something else
这样您就不必显式地将参数放入装饰器中,但如果用户指定它,您就可以检索它。
您可以解析到被调用函数的来源并检查 user
变量被使用了多少次,如果它大于 1 那么您可以使用变量 [=12= 调用该函数]:
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