![](/img/trans.png)
[英]Understanding the use of multiple python decorators in a single statement
[英]Python - ambiguity with decorators receiving a single arg
我正在尝试编写一个装饰器,它得到一个arg,即
@Printer(1)
def f():
print 3
因此,我天真地尝试了:
class Printer:
def __init__(self,num):
self.__num=num
def __call__(self,func):
def wrapped(*args,**kargs):
print self.__num
return func(*args,**kargs**)
return wrapped
可以,但是它也可以用作不接受arg的装饰器,即
@Printer
def a():
print 3
我该如何预防?
好吧,从某种意义上来说,已经有效地防止了调用a()
工作。
但是要在定义函数时停止它,我想您必须更改__init__
来检查num
的类型:
def __init__(self,num):
if callable(num):
raise TypeError('Printer decorator takes an argument')
self.__num=num
不过,我不知道这是否值得。 它已经不能按原样工作; 您实际上是在要求使用鸭子式语言来强制实参的类型。
您确定它没有参数就可以工作吗? 如果我将它们保留在外面,则会收到以下错误消息:
Traceback (most recent call last): File "/tmp/blah.py", line 28, in ? a() TypeError: __call__() takes exactly 2 arguments (1 given)
但是,如果基于类的定义不适合您,则可以尝试使用该替代定义。
def Printer(num):
def wrapper(func):
def wrapped(*args, **kwargs):
print num
return func(*args, **kwargs)
return wrapped
return wrapper
装饰器是@
运算后的表达式。 在第一种情况下,这是Printer
的一个实例,所以发生的事情(几乎)等同于
decorator = Printer(1) # an instance of Printer, the "1" is given to __init__
def f():
print 3
f = decorator(f) # == dec.__call__(f) , so in the end f is "wrapped"
在第二种情况下,这是打印机类,因此您有
decorator = Printer # the class
def a():
print 3
a = decorator(a) # == Printer(a), so a is an instance of Printer
因此,即使它可以工作(因为Printer
的构造函数需要一个额外的参数,就像__call__
一样),却是完全不同的事情。
防止这种情况的python方法通常是:不要这样做。 弄清楚装饰器的工作原理(例如在文档字符串中),然后相信人们在做正确的事情。
如果您真的想要检查, Eevee的答案提供了一种捕获此错误的方法(当然,在运行时-这是Python)。
我想不出理想的答案,但是如果您强制使用关键字参数实例化Printer类,则它永远不会尝试通过装饰器本身实例化,因为它仅处理非关键字参数:
def __init__(self,**kwargs):
self.__num=kwargs["num"]
...
@Printer(num=1)
def a():
print 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.