2012-06-05 15 views
5

Mam klasę o nazwie Serwer, którą można uruchomić i zatrzymać. Niektórych metod nie należy wywoływać, dopóki nie zostanie uruchomiony serwer, w którym to przypadku powinien zostać zgłoszony wyjątek NotConnectedException. Czy istnieje sposób wywołania metody przed każdą metodą w klasie i określenia, czy zmienna klasy _started ma wartość True?Sprawdź warunek przed wywołaniem metody

Próbowałem użyć dekoratora, ale funkcja dekoratora nie ma dostępu do zmiennej klasy. Starałem się zrobić coś takiego:

class Server(object): 
    _started = False 
    def started(self): 
     if(self._started == False): 
      raise NotConnectedException 

    @started 
    def doServerAction(self): 
     ... 
+0

czy próbowałeś umieścić dekorator bezpośrednio w klasie? Nie pracowałem wystarczająco na dekoratorach, aby wiedzieć, jak dobrze by to działało, ale właśnie tam zacznę szukać – inspectorG4dget

+0

jak ten [post] (http://stackoverflow.com/questions/2366713/can-a-python-decorator- z-an-instance-method-access-the-class) powiedział, że jeśli jest to python2.6 lub nowszy, istnieje sposób, aby twój dekorator mógł uzyskać dostęp do zmiennej klasy – xvatar

+0

@ inspectorG4dget Tak, dekorator jest w klasie. – BlueVoid

Odpowiedz

8

Pamiętaj, co dekoratorzy :

@decorate 
def foo(...): 
    ... 

jest dokładnie równoważne:

def foo(...): 
    ... 
foo = decorate(foo) 

Dekorator nazywa funkcję , więc wywołanie pierwszego parametru self nie powoduje sens. Również dekorator jest wywoływany w funkcji, gdy jest zdefiniowany, a to, co powraca, jest używane zamiast funkcji. Więc nawet jeśli twój dekorator started nie rzuciłby AttributeError, próbując uzyskać dostęp do atrybutu funkcji _started, zwróciłby on None, co sprawi, że wszystkie twoje metody zostaną ustawione na None, a zatem nawet nie będą możliwe do wywołania.

Co chcesz, jest coś takiego:

import functools 

def started(func): 
    @functools.wraps(func) 
    def wrapper(self, *args, **kwargs): 
     if not self._started: 
      raise ... 
     else: 
      return func(self, *args, **kwargs) 
    return wrapper 

Prawie wszyscy dekoratorzy są tej formy; biorą funkcję, tworzą owijkę, która robi coś "wokół" odebranej funkcji, a następnie zwracają opakowanie. Korzystanie z functools.wraps jest wygodne, jeśli kiedykolwiek będziesz pracował z tym kodem w interaktywnej sesji tłumacza; automatycznie aktualizuje funkcję wrapper z nazwą i docstrowaniem oryginalnej funkcji, co sprawia, że ​​udekorowane funkcje "wyglądają jak" oryginalną funkcję nieco więcej.

Nie ma znaczenia, czy jest to zdefiniowane w klasie, czy nie.

+0

To jest dokładnie to, czego szukałem. Dziękuję Ci! – BlueVoid

Powiązane problemy