2012-05-23 20 views
15

Czy możliwe jest dekorator funkcja warunkowo. Na przykład chcę ozdobić funkcję foo() funkcją timera (timeit) tylko wykonaniem _performance_analysis jest True (patrz poniższy kod psuedo).jak zrobić dekorator warunkowy w 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) 

Odpowiedz

20

Dekoratorzy są po prostu callables zwracające zastępstwo, ewentualnie taką samą funkcję, owijki, albo coś zupełnie innego. Jako takie, można utworzyć dekorator Warunkowo:

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) 

Teraz można go używać tak:

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

Dzięki! Sekcja komentarzy nie jest formatowana, dlatego dodałem przykładowy kod do oryginalnej odpowiedzi. Czy możesz wyjaśnić, dlaczego funkcja czasowa nie jest wywoływana? – cfpete

+0

Dekorator jest stosowany w czasie importu, więc zmienne instancji nie są w tym czasie konsultowane. Musiałbyś napisać do tego innego dekoratora, który sprawdzałby siebie po wywołaniu. Poza zakresem tego formatu Q i komentarza. :-) –

+0

Jak bym go używał, jeśli chcę użyć tego na metodach opartych na klasach, np. Widokach opartych na klasie Django. Tam musimy użyć 'method_decorator'. Jak uczynić ten kod zgodny z tym? – PythonEnthusiast

4

Jak o:

def foo(): 
    ... 

if doing_performance_analysis: 
    foo = timeit(foo) 

sobie wyobrazić nawet można zawinąć to do dekoratora, który wziąłby logiczną flagi i inny dekorator, i stosuje się tylko ten ostatni, gdy flaga jest ustawiona na True :

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

Dekorator jest po prostu funkcją stosowaną do innej funkcji. Można stosować go ręcznie:

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

if doing_performance_analysis: 
    foo = timeit(foo) 
0

odpowiedź Blckknght jest wielki, jeśli chcesz zrobić sprawdzanie przy każdym wywołaniu funkcji, ale jeśli masz ustawienie, które możesz przeczytać raz i nigdy się nie zmienia, możesz nie chcieć sprawdzać ustawienia za każdym razem, gdy wywoływana funkcja jest wywoływana. W niektórych z naszych wysokowydajnych demonów w pracy napisałem dekorator, który sprawdza plik ustawień raz, gdy najpierw jest załadowany plik Pythona i decyduje, czy powinien go zawinąć, czy nie.

Oto próbka

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 

Zakładając, że log_function_call rejestruje swoje połączenia do bazy danych, pliku dziennika lub cokolwiek i że config.get („RUN_TIMED_FUNCTIONS”) sprawdza konfigurację globalną, a następnie dodanie @timed dekorator do funkcji sprawdzi raz przy obciążeniu, aby sprawdzić, czy mierzysz czas na tym serwerze, środowisku itp., a jeśli nie, to nie zmieni to wykonania funkcji w produkcji ani w innych środowiskach, w których zależy Ci na wydajności.

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