python exception introspection hasattr

python - hasattr jquery



Comprobando la existencia del miembro en Python (5)

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 de instance debe existir, entonces use el segundo estilo de código. Si no tener instance es tan típico como tener una instance , entonces use el primer estilo.

En el caso específico de crear un singleton, me inclino a ir con el primer estilo, porque la creación de un singleton es un caso de uso típico. :-)

Regularmente quiero verificar 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 así:

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: se agregó el @classmethod ... Pero tenga en cuenta que la pregunta no es sobre cómo hacer un singleton, sino 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, típicamente, el método se llama muchas veces.


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 Pythonistas suelen sugerir que EAFP es mejor, con argumentos en el estilo de "¿y si un proceso crea el archivo entre el momento en que lo prueba y el momento en que intenta crearlo usted mismo?". Este argumento no se aplica aquí, pero es la idea general. Las excepciones no deben tratarse como demasiado excepcionales.

En lo que respecta al rendimiento en su caso, desde la configuración de los gestores de excepción (la palabra clave try ) es muy barato en CPython mientras se crea una excepción (la palabra clave raise y la creación de excepción interna) es relativamente costosa. Con el método №2 se generaría una excepción sólo una vez; luego, solo usa la propiedad.


Solo traté de 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. También me parece más legible, de todos modos depende del caso, esta prueba fue muy simple, tal vez necesitaría una más compleja.


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

Vi http://code.activestate.com/recipes/52558/ como una forma de hacer esto, también. Copia no commentada 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)


Un poco fuera de tema en la forma de usarlo. Los singletons están sobrevalorados, y un método de "estado compartido" es tan eficaz, y sobre todo, 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 haces:

obj = Borg()

tendrá la misma información, o será de alguna manera la misma instancia.