Pregunta

Regularmente quiero comprobar si un objeto tiene un miembro o no. Un ejemplo es la creación de un singleton en una función. Para ese propósito, puedes usar hasattr de esta manera:

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

Pero también puedes hacer esto:

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

¿Un método es mejor que el otro?

Editar: Agregó el @classmethod ... Pero tenga en cuenta que la pregunta es no sobre cómo hacer un singleton pero cómo verificar la presencia de un miembro en un objeto.

Editar: Para ese ejemplo, un uso típico sería:

s = Foo.singleton()

Entonces s es un objeto de tipo Foo , el mismo cada vez. Y, normalmente, el método se llama muchas veces.

¿Fue útil?

Solución

Estas son dos metodologías diferentes: ?1 es LBYL (mira antes de saltar) y ?2 es EAFP (más fácil pedir perdón que permiso).

Los pitonistas suelen sugerir que EAFP es mejor, con argumentos en estilo de " ¿qué sucede si un proceso crea el archivo entre el momento en que lo pruebas y el momento en que intentas crearlo tú mismo? " Este argumento no se aplica aquí, pero es la idea general. Las excepciones no deben tratarse como también excepcionales.

En cuanto a rendimiento, en su caso, ya que la configuración de los administradores de excepciones (la palabra clave try ) es muy barata en CPython al tiempo que se crea una excepción (la palabra clave raise y la excepción interna) la creación) es lo que es relativamente costoso: utilizando el método ?2, la excepción se generaría solo una vez; después, solo usas la propiedad.

Otros consejos

Acabo de intentar medir los tiempos:

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

En mi máquina:

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

Parece que try / except es más rápido. Me parece que también es más legible, de todas formas, según el caso, esta prueba fue muy simple, tal vez necesitarías una más compleja.

Depende de qué caso sea " típico " ;, porque las excepciones deben modelar, bueno, las condiciones atípicas. Entonces, si el caso típico es que el atributo instance debería existir, entonces use el segundo estilo de código. Si no tener instance es tan típico como tener instance , use el primer estilo.

En el caso específico de crear un singleton, me inclino por ir con el primer estilo, porque crear un singleton el tiempo inicial es un caso de uso típico. :-)

Un poco fuera de tema en la forma de usarlo. Los Singletons están sobrevalorados, y un " estado compartido " El método es tan efectivo y, en su mayoría, muy limpio en Python, por ejemplo:

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

Ahora cada vez que lo hagas:

obj = Borg()

tendrá la misma información o, en cierto modo, será la misma instancia.

Tengo que estar de acuerdo con Chris. Recuerde, no optimice hasta que realmente necesite hacerlo. Realmente dudo que verificar la existencia vaya a ser un cuello de botella en cualquier programa razonable.

Sí vi http://code.activestate.com/recipes/52558/ como una forma de hacer esto, también. Copia sin comentarios de ese código (" spam " es solo un método aleatorio que tiene la interfaz de clase):

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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top