2012-06-05 19 views
5

Tengo una clase llamada Servidor que se puede iniciar y detener. Ciertos métodos no deben invocarse a menos que el servidor se inicie, en cuyo caso se debe generar una NotConnectedException. ¿Existe alguna forma de invocar un método antes de cada método en una clase y determinar si la variable de clase _started está establecida en True?Comprobar condición antes de llamar al método

Intenté usar un decorador, pero la función de decorador no tiene acceso a la variable de clase. Yo estaba tratando de hacer algo como esto:

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

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

¿Intentó poner el decorador directamente en la clase? No he trabajado lo suficiente en decoradores para saber qué tan bien funcionaría esto, pero es donde empezaría a buscar – inspectorG4dget

+0

como este [post] (http://stackoverflow.com/questions/2366713/can-a-python-decorator- of-an-instance-method-access-the-class) dijo, si es python2.6 o posterior, hay una forma para que su decorador acceda a la variable de clase – xvatar

+0

@ inspectorG4dget Sí, el decorador pertenece a la clase. – BlueVoid

Respuesta

8

Recuerda lo decoradores son:

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

es exactamente equivalente a:

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

El decorador se llama la función , por lo que llamar al primer parámetro auto no hace sentido. Además, se llama al decorador sobre la función cuando está definida, y lo que devuelve se usa en lugar de la función. Así que incluso si su decorador started no arrojó un AttributeError al intentar acceder al atributo _started de una función, devolvería None, haciendo que todos sus métodos estén configurados en None, y por lo tanto ni siquiera se puedan llamar.

Lo que quiere decir algo como esto:

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 

Casi todos los decoradores son de esta forma; toman una función, crean un contenedor que hace algo "alrededor" de la función recibida, y luego devuelven el contenedor. El uso de functools.wraps aquí es una ventaja si alguna vez termina trabajando con este código en una sesión interactiva de intérprete; automáticamente actualiza la función wrapper con el nombre y la función de docstring de la función original, lo que hace que las funciones decoradas "se parezcan" a la función original un poco más.

No importa si esto se define dentro de la clase o no.

+0

Esto es exactamente lo que estaba buscando. ¡Gracias! – BlueVoid

Cuestiones relacionadas