2012-05-23 14 views
15

E 'possibile decoratore una funzione in modo condizionale. Ad esempio, desidero decorare la funzione foo() con una funzione timer (timeit) solo doing_performance_analysis è True (vedere il codice psuedo di seguito).come fare un decoratore condizionale in python 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) 

risposta

20

decoratori sono semplicemente callable che restituiscono una sostituzione, opzionalmente la stessa funzione, un involucro, o qualcosa di completamente diverso. Come tale, è possibile creare un decoratore condizionale:

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) 

Ora è possibile utilizzare in questo modo:

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

Grazie! La sezione dei commenti non viene formattata, quindi ho aggiunto il codice di esempio alla tua risposta originale. Puoi spiegare perché non viene chiamata la funzione di cronometraggio? – cfpete

+0

Il decoratore viene applicato al momento dell'importazione, quindi le variabili di istanza non vengono consultate in quel momento. Dovresti scrivere un decoratore diverso per questo, uno che ispeziona te stesso quando viene chiamato. Fuori campo per questo Q e il formato dei commenti. :-) –

+0

Come dovrei usarlo se voglio usare questo su metodi basati su classi, cioè viste basate su classi Django. Laggiù dobbiamo usare 'method_decorator'. Come rendere questo codice compatibile con quello? – PythonEnthusiast

4

ne dite:

def foo(): 
    ... 

if doing_performance_analysis: 
    foo = timeit(foo) 

immagino si potrebbe anche avvolgere questo in un decoratore che avrebbe preso una bandiera booleano e un altro decoratore, e si applicherebbe solo il secondo se il flag è impostato su True :

9

Un decoratore è semplicemente una funzione applicata a un'altra funzione. È possibile applicare manualmente:

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

if doing_performance_analysis: 
    foo = timeit(foo) 
0

risposta di Blckknght è grande se si vuole fare la verifica ogni volta che si chiama la funzione, ma se si dispone di un'impostazione che è possibile leggere una volta e non modificare mai, è possibile che non si desideri controllare l'impostazione ogni volta che viene chiamata la funzione decorata. In alcuni dei nostri demoni ad alte prestazioni sul lavoro ho scritto un decoratore che controlla un file di impostazione una volta quando il file python viene caricato per la prima volta e decide se deve essere incluso o meno.

Ecco un esempio

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 

Supponendo che log_function_call registra la chiamata a un database, file di log, o qualsiasi altra cosa e che config.get ('RUN_TIMED_FUNCTIONS') controlla la configurazione globale, quindi aggiungendo il decoratore @timed a una funzione controllerà una volta sul carico per vedere se si sta cronometrando su questo server, ambiente, ecc. e in caso contrario non cambierà l'esecuzione della funzione in produzione o negli altri ambienti in cui si cura delle prestazioni.

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()