Aşağıdaki iki kod parçasının neredeyse eşdeğer olduğu iyi bilinmektedir:
@dec
def foo():
pass foo = dec(foo)
############################################
foo = dec(foo)
Yaygın bir hata, @
sadece en soldaki argümanı gizlediğini düşünmektir .
@dec(1, 2, 3)
def foo():
pass
###########################################
foo = dec(foo, 1, 2, 3)
Yukarıda nasıl @
çalışılırsa dekoratörler yazmak çok daha kolay olurdu . Ne yazık ki, işler böyle yapılmıyor.
Wait
Program yürütmesini birkaç saniyeliğine engelleyen bir dekoratörü düşünün . Bir Bekleme süresini geçmezseniz, varsayılan değer 1 saniyedir. Kullanım durumları aşağıda gösterilmiştir.
##################################################
@Wait
def print_something(something):
print(something)
##################################################
@Wait(3)
def print_something_else(something_else):
print(something_else)
##################################################
@Wait(delay=3)
def print_something_else(something_else):
print(something_else)
Böyle Wait
bir argüman olduğunda , @Wait(3)
çağrı başka bir şey Wait(3)
gerçekleşmeden önce yürütülür .
Yani, aşağıdaki iki kod eşdeğeri
@Wait(3)
def print_something_else(something_else):
print(something_else)
###############################################
return_value = Wait(3)
@return_value
def print_something_else(something_else):
print(something_else)
Bu bir problem.
if `Wait` has no arguments:
`Wait` is the decorator.
else: # `Wait` receives arguments
`Wait` is not the decorator itself.
Instead, `Wait` ***returns*** the decorator
Bir çözüm aşağıda gösterilmiştir:
Aşağıdaki sınıfı oluşturarak başlayalım DelayedDecorator
:
class DelayedDecorator:
def __init__(i, cls, *args, **kwargs):
print("Delayed Decorator __init__", cls, args, kwargs)
i._cls = cls
i._args = args
i._kwargs = kwargs
def __call__(i, func):
print("Delayed Decorator __call__", func)
if not (callable(func)):
import io
with io.StringIO() as ss:
print(
"If only one input, input must be callable",
"Instead, received:",
repr(func),
sep="\n",
file=ss
)
msg = ss.getvalue()
raise TypeError(msg)
return i._cls(func, *i._args, **i._kwargs)
Şimdi şöyle yazabiliriz:
dec = DelayedDecorator(Wait, delay=4)
@dec
def delayed_print(something):
print(something)
Bunu not et:
dec
birden fazla argümanı kabul etmiyor.
dec
yalnızca kaydırılacak işlevi kabul eder.
import inspect class PolyArgDecoratorMeta (type): def call (Bekle, * args, ** kwargs): dene: arg_count = len (args) eğer (arg_count == 1): eğer çağrılabilir ise (args [0]): SuperClass = incele. getmro (PolyArgDecoratorMeta) [1] r = Süper Sınıf. aramak (Wait, args [0]) else: r = DelayedDecorator (Wait, * args, ** kwargs) else: r = DelayedDecorator (Wait, * args, ** kwargs) nihayet: dönüş dönüşü r
içe aktarma zaman sınıfı Bekleyin (metaclass = PolyArgDecoratorMeta): def init (i, func, delay = 2): i._func = func i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
Aşağıdaki iki kod parçası eşdeğerdir:
@Wait
def print_something(something):
print (something)
##################################################
def print_something(something):
print(something)
print_something = Wait(print_something)
"something"
Konsola çok yavaş yazdırabiliriz :
print_something("something")
#################################################
@Wait(delay=1)
def print_something_else(something_else):
print(something_else)
##################################################
def print_something_else(something_else):
print(something_else)
dd = DelayedDecorator(Wait, delay=1)
print_something_else = dd(print_something_else)
##################################################
print_something_else("something")
Son Notlar
Çok fazla kod gibi görünebilir, ancak sınıfları DelayedDecorator
ve PolyArgDecoratorMeta
her seferinde yazmak zorunda değilsiniz . Kişisel olarak aşağıdaki gibi bir şey yazmanız gereken tek kod, oldukça kısa:
from PolyArgDecoratorMeta import PolyArgDecoratorMeta
import time
class Wait(metaclass=PolyArgDecoratorMeta):
def __init__(i, func, delay = 2):
i._func = func
i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
execute_complete_reservation
iki parametre alır, ancak bir parametre geçirirsiniz. Dekoratörler, diğer fonksiyonların içine sarma fonksiyonları için sadece sözdizimsel şekerdir. Eksiksiz belgeler için docs.python.org/reference/compound_stmts.html#function sayfasına bakın .