[英]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.