python class-method getattr

__getattr__ para variables estáticas/de clase en python



class-method (5)

(Sé que esta es una pregunta antigua, pero como todas las demás respuestas usan una metaclase ...)

Puede usar el siguiente descriptor de classproperty simple:

class classproperty(object): """ @classmethod+@property """ def __init__(self, f): self.f = classmethod(f) def __get__(self, *a): return self.f.__get__(*a)()

Utilízalo como:

class MyClass(object): @classproperty def Foo(cls): do_something() return 1 @classproperty def Bar(cls): do_something_else() return 2

Tengo una clase como:

class MyClass: Foo = 1 Bar = 2

Siempre que se invoca MyClass.Foo o MyClass.Bar , necesito que se invoque un método personalizado antes de que se devuelva el valor. ¿Es posible en Python? Sé que es posible si creo una instancia de la clase y puedo definir mi propio método __getattr__ . Pero mi scnenario implica usar esta clase como tal sin crear ninguna instancia de ella.

También necesito que se invoque un método __str__ personalizado cuando se invoca str(MyClass.Foo) . ¿Python proporciona tal opción?


Dependiendo del caso utilizo este patrón.

class _TheRealClass: def __getattr__(self, attr): pass LooksLikeAClass = _TheRealClass()

Luego lo importas y lo usas.

from foo import LooksLikeAClass LooksLikeAClass.some_attribute

Esto evita el uso de metaclase, y maneja algunos casos de uso.


Nadie sorprendido señaló este:

class FooType(type): @property def Foo(cls): return "foo!" @property def Bar(cls): return "bar!" class MyClass(metaclass=FooType): pass

Trabajos:

>>> MyClass.Foo ''foo!'' >>> MyClass.Bar ''bar!''

(para Python 2.x, cambie la definición de MyClass a:

class MyClass(object): __metaclass__ = FooType

)

Lo que dicen las otras respuestas sobre str es cierto para esta solución: debe implementarse en el tipo que se devuelve.


Para el primero, deberá crear una metaclase y definir __getattr__() en eso.

class MyMetaclass(type): def __getattr__(self, name): return ''%s result'' % name class MyClass(object): __metaclass__ = MyMetaclass print MyClass.Foo

Para el segundo, no. Al llamar a str(MyClass.Foo) invoca MyClass.Foo.__str__() , por lo que deberá devolver un tipo apropiado para MyClass.Foo .


__getattr__() y __str__() para un objeto se encuentran en su clase, por lo que si desea personalizar esas cosas para una clase, necesita la clase de una clase. Una metaclase.

class FooType(type): def _foo_func(cls): return ''foo!'' def _bar_func(cls): return ''bar!'' def __getattr__(cls, key): if key == ''Foo'': return cls._foo_func() elif key == ''Bar'': return cls._bar_func() raise AttributeError(key) def __str__(cls): return ''custom str for %s'' % (cls.__name__,) class MyClass: __metaclass__ = FooType # in python 3: # class MyClass(metaclass=FooType): # pass print MyClass.Foo print MyClass.Bar print str(MyClass)

impresión:

foo! bar! custom str for MyClass

Y no, un objeto no puede interceptar una solicitud para una cadena de uno de sus atributos. El objeto devuelto para el atributo debe definir su propio __str__() .