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.
ensure_black
está devolviendo un método _aux
que no está decorado por @staticmethod
Puede devolver un método no estático a un método estático