2012-05-23 35 views
15

Bir işlevin koşullu olarak çözülmesi mümkün mü? Örneğin, foo() işlevini bir zamanlayıcı işleviyle (timeit) yalnızca 0_yapıyor (aşağıdaki psuedo koduna bakın) ile dekore etmek istiyorum.python'da koşullu bir dekoratör nasıl yapılır 2.6

if doing_performance_analysis: 
    @timeit 
    def foo(): 
    """ 
    do something, timeit function will return the time it takes 
    """ 
    time.sleep(2) 
else: 
    def foo(): 
    time.sleep(2) 

cevap

20

Dekoratörler sadece bir yedek, isteğe bağlı olarak aynı işlevi, bir sarmalayıcı veya tamamen farklı bir şey dönmek callables vardır.

class conditional_decorator(object): 
    def __init__(self, dec, condition): 
     self.decorator = dec 
     self.condition = condition 

    def __call__(self, func): 
     if not self.condition: 
      # Return the function unchanged, not decorated. 
      return func 
     return self.decorator(func) 

Şimdi bu gibi kullanabilirsiniz: Bunun gibi, bir koşullu dekoratör yaratabilecek

@conditional_decorator(timeit, doing_performance_analysis) 
def foo(): 
    time.sleep(2) 
+0

Teşekkürler! Yorum bölümü biçimlenmiyor, bu yüzden örnek kodu orijinal cevabınıza ekledim. Zamanlama fonksiyonunun neden çağrılmadığını açıklayabilir misiniz? – cfpete

+0

Dekoratör içe aktarma zamanında uygulanır, bu nedenle örnek değişkenlere bu anda başvurulmaz. Bunun için farklı bir dekoratör yazmalısın. Bu Q ve yorum formatı için kapsam dışı. :-) –

+0

Bunu, sınıf tabanlı yöntemlerde kullanmak istiyorum, Django Sınıfı temelli görünümler için nasıl kullanırdım. Orada 'method_decorator' kullanmak zorundayız. Bu kod nasıl uyumlu hale getirilir? – PythonEnthusiast

4

ne dersiniz:

def foo(): 
    ... 

if doing_performance_analysis: 
    foo = timeit(foo) 

ben bile bir boolean bayrak ve başka dekoratör götürecek bir dekoratör içine bu sarabilirdiniz ve bayrak True olarak ayarlanırsa, yalnızca sonuncu geçerli olacak hayal :

def cond_decorator(flag, dec): 
    def decorate(fn): 
     return dec(fn) if flag else fn 
    return decorate 

@cond_decorator(doing_performance_analysis, timeit) 
def foo(): 
    ... 
9

Bir dekoratör basitçe başka bir işleve uygulanan bir işlevdir. Elle uygulayabilirsiniz:

def foo(): 
    # whatever 
    time.sleep(2) 

if doing_performance_analysis: 
    foo = timeit(foo) 
0

Eğer işlevi çağırmak her zaman kontrol yapmak istiyorsanız Blckknght cevabı büyük, ancak bir kez okuyabileceğiniz ve hiçbir zaman değiştiremeyeceğiniz bir ayarınız varsa, dekore edilen fonksiyon çağrıldığında her zaman ayarı kontrol etmek istemeyebilirsiniz. Yüksek performanslı çalışmalarımızın bazılarında, python dosyası ilk kez yüklendiğinde bir ayar dosyasını kontrol eden bir dekoratör yazdım ve onu paketleyip göndermeyeceğine karar verdim. İşte

örnek

def timed(f): 
    def wrapper(*args, **kwargs): 
     start = datetime.datetime.utcnow() 
     return_value = f(*args, **kwargs) 
     end = datetime.datetime.utcnow() 
     duration = end - start 

     log_function_call(module=f.__module__, function=f.__name__, start=__start__, end=__end__, duration=duration.total_seconds()) 
    if config.get('RUN_TIMED_FUNCTIONS'): 
     return wrapper 
    return f 

o log_function_call varsayarsak bir veritabanı, kayıt dosyasına ya da her neyse ve bu config.get için çağrı kaydeder olduğu ('RUN_TIMED_FUNCTIONS') daha sonra @timed dekoratör ekleyerek, küresel yapılandırmasını denetler bir işleve, bu sunucuda, ortamda, vb. zamanlama olup olmadığınızı görmek için yüklendikten sonra bir kez kontrol edeceksiniz ve eğer değilse, bu, işlevin veya performansla ilgilendiğiniz diğer ortamların işlevini değiştirmeyecektir.

0
use_decorator = False 

class myDecorator(object): 
    def __init__(self, f): 
      self.f = f 

    def __call__(self): 
      print "Decorated running..." 
      print "Entering", self.f.__name__ 
      self.f() 
      print "Exited", self.f.__name__ 


def null(a): 
    return a 


if use_decorator == False : 
    myDecorator = null 


@myDecorator 
def CoreFunction(): 
    print "Core Function running" 

CoreFunction() 
İlgili konular