Вопрос

Я регулярно хочу проверить, есть ли у объекта член или нет.Примером может служить создание синглтона в функции.Для этой цели вы можете использовать hasattr так:

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

Но вы также можете сделать это:

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

Является ли один метод лучше другого?

Редактировать: Добавлен @classmethod ...Но обратите внимание, что вопрос нет о том, как сделать синглтон, но как проверить наличие члена в объекте.

Редактировать: Для этого примера типичным использованием будет:

s = Foo.singleton()

Затем s это объект типа Foo, каждый раз одно и то же.И, как правило, метод вызывается много раз.

Это было полезно?

Решение

Это две разные методики:№1 – это LBYL (посмотри, прежде чем прыгнуть) и №2 – EAFP (проще попросить прощения, чем разрешения).

Питонисты обычно предполагают, что EAFP лучше, приводя аргументы в стиле «что, если процесс создаст файл между моментом, когда вы его тестируете, и моментом, когда вы пытаетесь создать его самостоятельно?».Этот аргумент здесь неприменим, но это общая идея.Исключения не следует рассматривать как слишком исключительный.

С точки зрения производительности в вашем случае — с момента настройки менеджеров исключений ( try ключевое слово) очень дешево обходится в CPython при создании исключения (ключ raise создание ключевого слова и внутреннего исключения) является относительно дорогостоящим — при использовании метода №2 исключение будет вызвано только один раз;после этого вы просто используете свойство.

Другие советы

Я просто пытался измерить время:

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

На моей машине:

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

Кажется, что try/Exception работает быстрее.Мне он также кажется более читабельным, в любом случае, в зависимости от случая, этот тест был очень простым, возможно, вам понадобится более сложный.

Это зависит от того, какой случай является «типичным», потому что исключения должны моделировать нетипичные условия.Итак, если типичный случай заключается в том, что instance Атрибут должен существовать, тогда используйте второй стиль кода.Если не иметь instance так же типично, как наличие instance, затем используйте первый стиль.

В конкретном случае создания синглтона я склоняюсь к первому стилю, поскольку создание синглтона в начальный момент является типичным вариантом использования.:-)

Немного не по теме в использовании.Синглтоны переоценены, а метод с «общим состоянием» столь же эффективен и, как правило, очень чист в Python, например:

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

Теперь каждый раз, когда вы это делаете:

obj = Borg()

он будет иметь ту же информацию или будет в некоторой степени одним и тем же экземпляром.

Я должен согласиться с Крисом.Помните: не оптимизируйте до тех пор, пока вам это действительно не понадобится.Я действительно сомневаюсь, что проверка существования станет узким местом в любой разумной программе.

я видел http://code.activestate.com/recipes/52558/ как способ сделать это тоже.Некомментированная копия этого кода («спам» — это просто случайный метод, который есть в интерфейсе класса):

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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top