from functools import wraps
def logged(func):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
@logged
def f(x):
"""does some math"""
return x + x * x
print f.__name__ # prints 'f'
print f.__doc__ # prints 'does some math'
Run Code Online (Sandbox Code Playgroud)
鉴于此示例代码,我将如何做@logged(variable)?
我试过这个
from functools import wraps
def logged(func):
def outer(var):
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
return outer
Run Code Online (Sandbox Code Playgroud)
我希望这样执行:logged(func)(session_variable)
但是不起作用.任何的想法?我希望能够做@logged和@logged(var)(甚至@logged(var1,var2))谢谢.
Sea*_*ira 11
这里的诀窍是,你必须反省你得到的东西:
def logged(*setting_args, **setting_kwargs):
no_args = False
if len(setting_args) == 1 \
and not setting_kwargs \
and callable(setting_args[0]):
# We were called without args
func = setting_args[0]
no_args = True
def outer(func):
@wraps(func)
def with_logging(*args, **kwargs):
print "{} was called".format(func.__name__)
print "Setting args are: {}".format(setting_args)
print "Setting keyword args are: {}".format(setting_kwargs)
return func(*args, **kwargs)
return with_logging
if no_args:
return outer(func)
else:
return outer
Run Code Online (Sandbox Code Playgroud)
这将适用于以下任何一项:
# No arguments
@logged
def some_function(x):
pass
# One or more arguments
@logged(1, 2, 3)
def some_function(x):
pass
# One or more keyword arguments
@logged(key=1, another_key=2)
def some_function(x):
pass
# A mix of the two
@logged(1, 2, key=3)
def some_function(x):
pass
Run Code Online (Sandbox Code Playgroud)
它不会,如果它被称为只有一个可调用的参数工作:
# This will break.
@logged(lambda: "Just for fun")
def some_function(x):
pass
Run Code Online (Sandbox Code Playgroud)
没有办法区分单个可调用设置和装饰器的无参数调用之间的区别.但是,您可以传递一个垃圾关键字arg来解决这个问题,如果您需要:
# This gets around the above limitation
@logged(lambda: "Just for fun", ignored=True)
def some_function(x):
pass
Run Code Online (Sandbox Code Playgroud)
这个问题已经有6年多了,并且已经有了答案。我遇到了同样的情况 - 必须更新代码中很多地方使用的装饰器,并且想要添加一个可选参数。
我能够使用不同的方法来完成它 - 来自《Python CookBook 3rd Edition》一书,第 9 章 - 9.6。定义带有可选 参数的装饰器。它提出问题,提出解决方案并以讨论结束(非常棒)。
解决方案:适用于Python 3.3+
from functools import wraps, partial
def logged(func=None, *, var1=None, var2=None):
if func is None:
return partial(logged, var1=var1, var2=var2)
@wraps(func)
def with_logging(*args, **kwargs):
print func.__name__ + " was called"
return func(*args, **kwargs)
return with_logging
Run Code Online (Sandbox Code Playgroud)
通过上述操作,您可以执行以下任一操作:
@logged
def f(x):
@logger(var1)
def f(x):
@logger(var1, var2)
def f(x)
Run Code Online (Sandbox Code Playgroud)
解释(最好在书上找)
要理解代码的工作原理,您需要深入了解装饰器如何应用于函数及其调用约定。
1. 简单的装饰器,例如:
# Example use
@logged
def add(x, y):
return x + y
Run Code Online (Sandbox Code Playgroud)
调用顺序如下:
def add(x, y):
return x + y
add = logged(add)
Run Code Online (Sandbox Code Playgroud)
在这种情况下,要包装的函数只是作为第一个参数传递给logging。因此,在解决方案中,logging() 的第一个参数是被包装的函数。所有其他参数都必须有默认值。
2. 装饰器接受参数:
@logged(level=logging.CRITICAL, name='example')
def spam():
print('Spam!')
Run Code Online (Sandbox Code Playgroud)
调用顺序如下:
def spam():
print('Spam!')
spam = logged(level=logging.CRITICAL, name='example')(spam)
Run Code Online (Sandbox Code Playgroud)
logged()上面的最后一行是如何调用带有参数的装饰器,即在要装饰的函数的初始调用中spam()未传递,因此我们func=None在logged定义中将其设置为可选的装饰器。因此,在第一次调用中仅传递参数。
这反过来又迫使其他参数由关键字指定。此外,当传递参数时,装饰器应该返回一个接受该函数并包装它的函数(参见第 9.5 节)。为此,该解决方案使用了一个巧妙的技巧,涉及
functools.partial. 具体来说,它只是返回自身的部分应用版本,其中除了要包装的函数之外的所有参数都是固定的。
| 归档时间: |
|
| 查看次数: |
2174 次 |
| 最近记录: |