patron - Python: @staticmethod con @property
patron singleton python (4)
yo quiero
Stats.singleton.twitter_count += 1
y pensé que podrí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 arroja 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)
El usuario kaizer.se estaba en algo en cuanto a la pregunta original. Avancé un poco más en términos de simplicidad, por lo que ahora solo se necesita 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 señaló, esta forma de crear un singleton 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á.
Los métodos estáticos no tienen 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í. Solo es de solo lectura, eso era todo lo que necesitaba (entonces 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
Los singletons 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
Los int
s de Python son diferentes de los simples object
s, por lo que no siempre es tan simple. Pero para tus propósitos, esto parece ser suficiente:
class Stats:
twitter_count = 0
Stats.twitter_count +=1
Stats.twitter_count +=1
assert Stats.twitter_count == 2
Siguiendo con lo que KyleAlanHale escribió:
Su ejemplo funciona muy bien, hasta que intentes y hagas:
Stats.singleton = 5
Esto no le dará un error, sobrescribirá la función, de modo que cuando escriba a continuación
single = Stats.singleton
print single
Obtendrás
5
Creo que es mejor que uses la respuesta de Kyle sin la decoración @classproperties.