Pergunta

Eu regularmente querer verificar se um objeto tem um membro ou não. Um exemplo é a criação de um singleton em uma função. Para esse efeito, você pode usar hasattr assim:

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

Mas você também pode fazer isso:

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

é um método melhor do outro?

Editar: Adicionado o @classmethod ... Mas nota que a questão é não sobre como fazer um singleton, mas como verificar a presença de um membro de um objeto .

Editar: Para que exemplo, um uso típico seria:

s = Foo.singleton()

Então s é um objeto do tipo Foo, o mesmo cada vez. E, geralmente, o método é chamado muitas vezes.

Foi útil?

Solução

Estas são duas metodologias diferentes:. ?1 é LBYL (olhar antes de saltar) e ?2 é EAFP (mais fácil pedir perdão do que permissão)

Pythonistas tipicamente sugerem que EAFP é melhor, com argumentos em estilo de "what if um processo cria o arquivo entre o momento em que você teste para ele e o tempo que você tentar criá-lo?". Este argumento não se aplica aqui, mas é a idéia geral. Exceções não deve ser tratado como muito excepcional.

Em termos de performance no seu caso -desde a criação de gestores de exceção (a palavra-chave try) é muito barato em CPython, criando uma exceção (a palavra-chave raise e criação de exceção interna) é o que é relativamente caros- usando o método ?2 exceção seria criado apenas uma vez; depois, você só usar a propriedade.

Outras dicas

Eu apenas tentei vezes medida:

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

Na minha 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 é mais rápido. Também parece mais legível para mim, de qualquer maneira depende do caso, este teste foi muito simples, talvez você precisa de um mais complexo.

Depende de qual caso é "típico", porque as exceções devem modelar, assim, condições atípicas. Assim, se o caso típico é que o atributo instance deveria existir, em seguida, usar o segundo estilo do código. Se não ter instance é tão típico como tendo instance, em seguida, usar o primeiro estilo.

No caso específico de criar um singleton, eu estou inclinado a ir com o primeiro estilo, porque a criação de um singleton o tempo inicial é um caso de uso típico. : -)

Um pouco off-topic na maneira de usá-lo. Singletons são avaliados em excesso, e um método de "estado compartilhado" é tão eficaz, e principalmente, muito limpa em python, por exemplo:

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

Agora, cada vez que você faz:

obj = Borg()

ela terá a mesma informação, ou, ser um pouco a mesma instância.

Eu tenho que concordar com Chris. Lembre-se, não otimizar até que você realmente precisa para fazê-lo. Eu realmente dúvida a verificação de existência vai ser um gargalo em qualquer programa razoável.

Eu vi http://code.activestate.com/recipes/52558/ como uma maneira de fazer isso também. cópia comentada desse código ( "spam" é apenas um método aleatório a interface de classe tem):

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top