Я думаю, что ваше решение не так уж плохо с оговоркой в том, что вы абсолютно необходимо заполнить что __dict__
до следующего init
вызывается снова или firstInitializationMethod()
будет называться более чем один раз. Это гарантировано в вашем примере из-за self.val = arg
.
Однако, если ваш Simpleton не выполнил никаких назначений внутри пространства имен экземпляров класса в своем вызове __init__
, ваше решение может выйти из строя.
Более простой и надежный способ, это просто использовать атрибут класса, как это:
class Singleton(Borg):
_first_initialization = True
def __init__(self,arg):
Borg.__init__(self)
if Singleton._first_initialization:
firstInitializationMethod()
Singleton._first_initialization = False
Вы можете проверить этот код, просто заменив firstInitializationMethod()
с печатью и создания некоторых Simpleton
объектов, чтобы увидеть, что это будет только дозвонились один раз.
Это работает и _first_initialization
не переписываются обратно True
на каждом __init__
вызов, потому что класс пространство имена отдельный из класса экземпляра имен и Борг влияет только на последний (а именно делает все экземпляры Simpleton использовать те же __dict__
).
Followup вопрос: Я попытался код с себя вместо Singleton и он все еще работал. Кажется, они решили одно и то же. Есть ли причина использовать Синглтон?
Рассмотрим этот код, используя эти два подхода, где SingletonSelfless
является одним использованием Singleton._first_initialization
, tinker()
только возвращение self.__first_initialization
:
a = Singleton('a')
print(a)
b = Singleton('b')
print(a,b)
c = Singleton('c')
print(a,b,c)
print(Singleton._first_initialization, a.tinker(),b.tinker(),c.tinker())
a = SingletonSelfless('a')
print(a)
b = SingletonSelfless('b')
print(a,b)
c = SingletonSelfless('c')
print(a,b,c)
print(SingletonSelfless._first_initialization, a.tinker(),b.tinker(),c.tinker())
и его вывод:
doing some init!!
a
b b
c c c
True False False False
doing some init!!
a
b b
c c c
False False False False
С практической точки зрения как работы, как мы хотели, еще есть четкая разница с _first_initialization
значения переменных (переменных).
Ответ довольно прост. Несмотря на то, что пространство имен классов и пространство имен экземпляров являются отдельными, экземпляр по-прежнему может получить доступ к пространству имен классов. Но это происходит только в том случае, когда пространство имен экземпляров экземпляра fallback - имеет абсолютный приоритет, но когда он не может найти имя в своем собственном экземпляре namepsace, он пытается использовать первый класс. Итак, давайте посмотрим на __init__
в этом Singleton
:
class Singleton(Borg):
_first_initialization = True
def __init__(self,arg):
Borg.__init__(self)
if self._first_initialization:
print('doing some init!!')
self._first_initialization = False
self.val = arg
def tinker(self):
return self._first_initialization
def __str__(self): return self.val
Даже если экземпляр не имеет _first_initialization
нашего if
решается с помощью Singleton._first_initialization
. Однако установка self._first_initialization
на False
создает переменную _first_initialization
в пространстве имен экземпляров. Благодаря слишком Borg
всем нашим экземпляры один и те же __dict__
, так и на последующей инициализацию вызовов будет находиться в пространстве имен экземпляра класса (созданный при первом вызове __init__
со значением False
) и нашим условным оператором будет решить, как мы хотим _first_initialization
это - не делать еще firstInitializationMethod()
(здесь распечатать для демонстрации пурпуры).
Однако наши оригинальные _first_initialization
, находящиеся в пространстве имен классов, не изменились. Вот почему мы получаем True False False False
.
В SingletonSelfless
мы никогда не создаем _first_initialization
экземпляров класса, поэтому вызов tinker() будет возвращаться к пространству имен классов. Вот почему есть 4 фальши - все вызовы указывают на один и тот же объект (SingletonSelfless._first_initialization
bool variable).
В то время как в Singleton
у нас есть два разных объекта - один из пространства имен классов, а другой в пространстве имен экземпляров класса, разделяемых между экземплярами. Так зачем использовать Singleton.
вместо self.
? Ну, для начинающих с первым мы «сбережем» невероятно крошечный бит памяти, имея там только один _first_initialization bool! Но реальная причина в том, что сложнее сменить переменную, скрывающуюся в пространстве имен классов. Если мы используем self._first_initialization
и где-то в конце нашего кода что-то подобное произошло по какой-либо причине (или _shared_dict от Borg будет очищен или изменен затрагивающим, что бы жить там): a._first_initialization = 'Lol'
или в Singleton или его дочерний метод self._first_initialization = 'ROFL'
мы у вас возникнут серьезные проблемы, связанные с инициализацией новых объектов Singleton. С Singleton._first_initialization
было бы хорошо, так как переменная, используемая для инициализации может быть изменена только путем явного Singleton._first_initialization='bad idea'
Это частично не связано, но я попробовал код с 'self' вместо' Singleton', и он все еще работал. Кажется, они решили одно и то же. Есть ли причина использовать «Синглтон»? – vsocrates
@ thePhilosopher Они различаются. Я обновлю свой ответ, чтобы показать вам разницу. –
@ thePhilosopher Я обновил ответ со всей стеной текста относительно вашего последующего вопроса, но я надеюсь, что это достаточно читаемо, чтобы вы поняли. –