son que posicional opcionales metodos magicos los funciones decoradores argumentos argumento arg python decorator static-methods

posicional - que es*args en python



Decorador Python como método estático. (3)

Estoy intentando escribir una clase de python que usa una función decoradora que necesita información del estado de la instancia. Esto funciona según lo previsto, pero si hago del decorador un método estático de forma explícita, obtengo el siguiente error:

Traceback (most recent call last): File "tford.py", line 1, in <module> class TFord(object): File "tford.py", line 14, in TFord @ensure_black TypeError: ''staticmethod'' object is not callable

¿Por qué?

Aquí está el código:

class TFord(object): def __init__(self, color): self.color = color @staticmethod def ensure_black(func): def _aux(self, *args, **kwargs): if self.color == ''black'': return func(*args, **kwargs) else: return None return _aux @ensure_black def get(): return ''Here is your shiny new T-Ford'' if __name__ == ''__main__'': ford_red = TFord(''red'') ford_black = TFord(''black'') print ford_red.get() print ford_black.get()

Y si acabo de eliminar la línea @staticmethod , todo funciona, pero no entiendo por qué. ¿No debería necesitarse como primer argumento?


Las clases de Python se crean en tiempo de ejecución, después de evaluar el contenido de la declaración de clase. La clase se evalúa asignando todas las variables y funciones declaradas a un diccionario especial y utilizando ese diccionario para llamar al type.__new__ (vea cómo personalizar la creación de clases ).

Asi que,

class A(B): c = 1

es equivalente a:

A = type.__new__("A", (B,), {"c": 1})

Cuando se anota un método con @staticmethod, hay una magia especial que ocurre DESPUÉS de que la clase se haya creado con el type.__new__ . Dentro del alcance de la declaración de clase, la función @staticmethod es solo una instancia de un objeto staticmethod, al que no se puede llamar. Probablemente, el decorador solo se debe declarar por encima de la definición de clase en el mismo módulo O en un módulo "decorar" separado (depende de cuántos decoradores tenga). En general, los decoradores deben ser declarados fuera de una clase. Una excepción notable es la clase de propiedad (ver properties ). En su caso, tener el decorador dentro de una declaración de clase podría tener sentido si tuviera algo así como una clase de color:

class Color(object): def ___init__(self, color): self.color = color def ensure_same_color(f): ... black = Color("black") class TFord(object): def __init__(self, color): self.color = color @black.ensure_same_color def get(): return ''Here is your shiny new T-Ford''


No es así como se supone que se utiliza el staticmethod . staticmethod objetos staticmethod son descriptors que devuelven el objeto envuelto, por lo que solo funcionan cuando se accede como classname.staticmethodname . Ejemplo

class A(object): @staticmethod def f(): pass print A.f print A.__dict__["f"]

huellas dactilares

<function f at 0x8af45dc> <staticmethod object at 0x8aa6a94>

Dentro del alcance de A , siempre obtendrías el último objeto, que no es llamable.

Recomiendo encarecidamente mover el decorador al ámbito del módulo, ya que no parece pertenecer a la clase. Si desea mantenerlo dentro de la clase, no lo convierta en un staticmethod , sino que simplemente staticmethod al final del cuerpo de la clase; en este caso, no debe utilizarse desde fuera de la clase.