Question

Je veux régulièrement vérifier si un objet a un membre ou non. Un exemple est la création d'un singleton dans une fonction. Pour cela, vous pouvez utiliser hasattr comme ceci:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance

Mais vous pouvez aussi faire ceci:

class Foo(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Foo()
            return self.instance

Une méthode est-elle meilleure que l'autre?

Modifier: Le @classmethod a été ajouté ... Mais notez que la question est non de savoir comment créer un singleton, mais comment vérifier la présence d'un membre dans un objet.

Modifier: Pour cet exemple, une utilisation typique serait:

s = Foo.singleton()

Alors s est un objet de type Foo , identique à chaque fois. Et, généralement, la méthode est appelée plusieurs fois.

Était-ce utile?

La solution

Ce sont deux méthodologies différentes: ?1 est LBYL (à regarder avant de sauter) et ?2 est EAFP (plus facile de demander pardon que l’autorisation).

Les pythonistes suggèrent généralement que EAFP est préférable, avec des arguments dans le style "et si un processus crée le fichier entre le moment où vous le testez et celui où vous essayez de le créer vous-même?". Cet argument ne s'applique pas ici, mais c'est l'idée générale. Les exceptions ne doivent pas être considérées comme aussi exceptionnelles.

En termes de performances, dans votre cas, car la configuration de gestionnaires d'exceptions (le mot clé try ) est très économique dans CPython lors de la création d'une exception (le mot clé raise et l'exception interne). création) est ce qui est relativement coûteux - avec la méthode ?2, l’exception ne serait levée qu’une fois; ensuite, vous utilisez simplement la propriété.

Autres conseils

Je viens d'essayer de mesurer les temps:

class Foo(object):
    @classmethod
    def singleton(self):
        if not hasattr(self, 'instance'):
            self.instance = Foo()
        return self.instance



class Bar(object):
    @classmethod
    def singleton(self):
        try:
            return self.instance
        except AttributeError:
            self.instance = Bar()
            return self.instance



from time import time

n = 1000000
foo = [Foo() for i in xrange(0,n)]
bar = [Bar() for i in xrange(0,n)]

print "Objs created."
print


for times in xrange(1,4):
    t = time()
    for d in foo: d.singleton()
    print "#%d Foo pass in %f" % (times, time()-t)

    t = time()
    for d in bar: d.singleton()
    print "#%d Bar pass in %f" % (times, time()-t)

    print

Sur ma machine:

Objs created.

#1 Foo pass in 1.719000
#1 Bar pass in 1.140000

#2 Foo pass in 1.750000
#2 Bar pass in 1.187000

#3 Foo pass in 1.797000
#3 Bar pass in 1.203000

Il semble que try / except est plus rapide. Cela me semble aussi plus lisible, cela dépend quand même du cas, ce test était très simple, vous auriez peut-être besoin d’un test plus complexe.

Cela dépend du cas "typique", car les exceptions devraient modéliser, ainsi, des conditions atypiques. Ainsi, si le cas typique est que l'attribut instance devrait exister, utilisez le second style de code. Si ne pas avoir instance est aussi typique que d'avoir instance , utilisez le premier style.

Dans le cas spécifique de la création d'un singleton, je suis enclin à choisir le premier style, car la création d'un singleton l'heure initiale est un cas d'utilisation typique. : -)

Un peu hors sujet dans la façon de l'utiliser. Les singletons sont surestimés et un "état partagé" Cette méthode est aussi efficace et surtout très propre en python, par exemple:

class Borg:
    __shared_state = {}
    def __init__(self):
        self.__dict__ = self.__shared_state
    # and whatever else you want in your class -- that's all!

Maintenant, chaque fois que vous faites:

obj = Borg()

il aura la même information ou, un peu la même instance.

Je suis d'accord avec Chris. Rappelez-vous, n'optimisez pas avant d'avoir besoin de le faire. Je doute vraiment que le fait de vérifier l'existence existe un goulot d'étranglement dans tout programme raisonnable.

J'ai vu http://code.activestate.com/recipes/52558/ comme un moyen de le faire aussi. Copie non commentée de ce code ("spam" n'est qu'une méthode aléatoire utilisée par l'interface de classe):

class Singleton:
    class __impl:
        def spam(self):
            return id(self)
    __instance = None
    def __init__(self):
        if Singleton.__instance is None:
            Singleton.__instance = Singleton.__impl()
        self.__dict__['_Singleton__instance'] = Singleton.__instance
    def __getattr__(self, attr):
        return getattr(self.__instance, attr)
    def __setattr__(self, attr, value):
        return setattr(self.__instance, attr, value)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top