2009-11-08 8 views
29

Je veuxPython: @staticmethod avec @property

Stats.singleton.twitter_count += 1 

et je pensais que je pouvais faire

class Stats: 
    singleton_object = None 

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

Mais il renvoie une exception:

>>> 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

où 'singleton_object' est-il défini? – tonfa

+3

Où est défini "self"? – tonfa

+2

définir "ne fonctionne pas" – u0b34a0f6ae

Répondre

8

singletons sont inutiles 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 

int de Python s sont de simples differnt object s, il est donc pas toujours aussi simple que cela. Mais pour vos fins, cela semble être suffisant:

class Stats: 
    twitter_count = 0 

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

J'ai un peu de trame de fond, en ce sens que je veux un DB AppEngine.Objet de modèle à être un singleton (un seul objet Stats dans la base de données). Donc j'ai besoin d'avoir au moins une instance en mémoire. –

+1

Je ne comprends pas. Lorsque vous avez une base de données derrière cela, toutes les instances partagent déjà le même état, l'état d'une ligne dans votre base de données. Deux instances peuvent ne pas être identiques, mais tout ORM méritant ce nom s'assurera que changer l'un ou l'autre changera aussi l'autre. –

+32

Partout vous entendez des gens dire que les méthodes statiques et singletons sont inutiles en Python, yadda, yadda. Ce n'est pas bon. Singleton est un modèle valide et nécessaire. Ce que «nous» la plus grande communauté de programmation veut savoir, c'est «comment» nous sommes censés le faire de la «bonne façon». Toute réponse qui ne répond pas directement est, je pense, inutile. Pour ma part, je suis perplexe sur cette question. :-) Aidez-moi! – 010110110101

6

Les méthodes statiques ne le font pas avoir du sens en Python. C'est parce qu'ils ne font rien que les méthodes de classe ne peuvent pas, et les méthodes de classe sont beaucoup plus faciles à étendre dans le futur (quand plusieurs méthodes de classe s'utilisent, etc.).

Ce dont vous avez besoin est simplement une propriété de méthode de classe.

J'ai une propriété de méthode de classe de mon code ici. Il est en lecture seule seule, qui était tout ce que je avais besoin (donc le reste est un exercice au lecteur):

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

Je ne pense pas qu'il existe une réponse à votre «exercice pour le lecteur»; La méthode __set__ d'un descripteur de données n'est pas appelée lorsque vous effectuez une recherche sur une classe. La liaison est juste changée. –

+23

-1: les méthodes statiques sont un outil précieux et utile. – Reid

49

utilisateur kaizer.se était sur quelque chose d'aussi loin que la question initiale va. Je l'ai pris un peu plus loin en termes de simplicité, de sorte qu'il exige désormais qu'un seul décorateur:

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

Utilisation:

class Stats: 
    _current_instance = None 

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

Comme indiqué, cette façon de créer un singleton est pas un bon design pattern; si cela doit être fait, une usine de métaclasse est une bien meilleure façon de le faire. J'étais juste excité au sujet de la perspective d'une propriété de classe bien, ainsi, là c'est.

1

Faisant suite à ce que KyleAlanHale a écrit:

Son exemple fonctionne très bien, jusqu'à ce que vous essayez de faire:

Stats.singleton = 5 

Cela ne vous donnera pas une erreur, il écrase la fonction, de sorte que lorsque vous tapez ensuite

single = Stats.singleton 
print single 

vous obtiendrez

5 

Je pense qu'il vaut mieux utiliser la réponse de Kyle sans la décoration @classproperties.