2009-11-08 12 views
29

QuieroPython: @staticmethod con @property

Stats.singleton.twitter_count += 1 

y pensé que podía hacer

class Stats: 
    singleton_object = None 

    @property 
    @staticmethod 
    def singleton(): 
     if Stats.singleton_object: 
      return Stats.singleton_object 
     Stats.singleton_object = Stats() 
     return Stats.singleton() 

Pero se produce una excepción:

>>> Stats.singleton.a = "b" 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'property' object has only read-only attributes (assign to .a) 
+2

donde se define 'singleton_object'? – tonfa

+3

donde se define 'self'? – tonfa

+2

define "no funciona" – u0b34a0f6ae

Respuesta

8

Singleton no tienen sentido en Python.

class A: 
    class_var = object() 

# two objects 
a, b = A(), A() 

# same var everywhere 
assert a.class_var is b.class_var is A.class_var 

de Python int s son differnt desde simples object s, lo que no siempre es tan sencillo. Pero para sus propósitos, esto parece ser suficiente:

class Stats: 
    twitter_count = 0 

Stats.twitter_count +=1 
Stats.twitter_count +=1 
assert Stats.twitter_count == 2 
+0

Tengo un poco de una historia de fondo, en la que quiero un db AppEngine.El objeto modelo es un singleton (solo un objeto Stats en la base de datos). Entonces necesito tener al menos una instancia en la memoria. –

+1

No lo entiendo Cuando tienes un DB detrás de eso, todas las instancias ya comparten el mismo estado, el estado de una fila en tu DB. Es posible que dos instancias no sean idénticas, pero cualquier ORM que merezca ese nombre se asegurará de que el cambio también cambie el otro. –

+32

Todo el mundo oye a la gente decir que los métodos estáticos y los singletons no tienen sentido en Python, yadda, yadda. Eso es basura. Singleton es un patrón válido y necesario. Lo que "nosotros" la comunidad de programación más grande desea saber es "cómo" se supone que debemos hacerlo de la "manera correcta". Cualquier respuesta que no responde directamente es, creo, inútil. Yo, por mi parte, estoy perplejo en este tema. :-) ¡Ayuda! – 010110110101

6

Los métodos estáticos no lo hacen tiene sentido en Python. Eso es porque no hacen nada que los métodos de clase no puedan hacer, y son métodos de clase mucho más fáciles de extender en el futuro (cuando los métodos de clase múltiple se usan entre sí, etc.).

Lo que necesita es simplemente una propiedad de método de clase.

Tengo una propiedad de método de clase de mi código aquí. Está sólo lectura solamente, que era todo lo que necesitaba (por lo que el resto es un ejercicio para el lector):

class ClassProperty (property): 
    """Subclass property to make classmethod properties possible""" 
    def __get__(self, cls, owner): 
     return self.fget.__get__(None, owner)() 

# how I would use it 
class Stats: 
    singleton_object = None 
    @ClassProperty 
    @classmethod 
    def singleton(cls): 
     if cls.singleton_object is None: 
      cls.singleton_object = cls() 
     return cls.singleton_object 
+3

No creo que haya una respuesta a su "ejercicio para el lector"; el método __set__ del descriptor de datos no se llama cuando está realizando una búsqueda en una clase. El enlace simplemente se cambia. –

+23

-1: los métodos estáticos son una herramienta valiosa y útil. – Reid

49

El usuario kaizer.se estaba en algo tan lejos como la pregunta original. Tomé un paso más allá en términos de simplicidad, de modo que ahora sólo requiere un único decorador:

class classproperty(property): 
    def __get__(self, cls, owner): 
     return classmethod(self.fget).__get__(None, owner)() 

Uso:

class Stats: 
    _current_instance = None 

    @classproperty 
    def singleton(cls): 
     if cls._current_instance is None: 
      cls._current_instance = Stats() 
     return cls._current_instance 

Como se ha señalado, esta manera de crear un producto único no es un buen patrón de diseño; si eso debe hacerse, una fábrica de metaclass es una forma mucho mejor de hacerlo. Sin embargo, estaba entusiasmado con la perspectiva de una propiedad de clase, así que ahí está.

1

Siguiendo con lo que escribió KyleAlanHale:

Su ejemplo funciona muy bien, hasta que tratar de hacer:

Stats.singleton = 5 

Esto no le dará un error, se sobrescribirá la función, por lo que cuando se escribe al lado

single = Stats.singleton 
print single 

usted obtendrá

5 

Creo que es mejor que utilices la respuesta de Kyle sin la decoración @classproperties.