Почему wrapper_singleton.instance = None
не устанавливает экземпляр равным none каждый раз, когда создается экземпляр класса?
Поскольку эта часть кода выполняется только тогда, когда класс оформлен.
Это:
@singleton
class TheOne:
pass
функционально эквивалентно
class TheOne:
pass
TheOne = singleton(TheOne)
Обе версии кода фактически возвращают функцию через магию functools.wraps
, которая действует так, как если бы она былаобернутый, как прекрасно объясняет @ smarie здесь .
TheOne = singleton(TheOne)
print(TheOne)
# <function TheOne at 0x00000000029C4400>
Если вы удалите украшение @functools.wraps
, у вас будет поверхностный взгляд за кулисы:
def singleton(cls)
#@functools.wraps(cls)
def wrapper_singleton(*args, **kwargs): ...
TheOne = singleton(TheOne)
print(TheOne)
# <function singleton.<locals>.wrapper_singleton at 0x00000000029F4400>
Таким образом, имя TheOne
фактически назначено внутренней функции wrapper_singleton
вашей singleton
функции.
Следовательно, когда вы делаете TheOne()
, вы не создаете экземпляр класса напрямуюВы вызываете wrapper_singleton
, который делает это за вас.
Это означает, что функция singleton
вызывается только когда вы украшаете класс или делаете это вручную через TheOne = singleton(TheOne)
.Он определяет wrapper_singleton
, создает для него дополнительный атрибут instance
(чтобы if not wrapper_singleton.instance
не вызывал AttributeError), а затем возвращает его под именем TheOne
.
.снова украсив класс.
class TheOne:
def __init__(self, arg):
self.arg = arg
TheOne = singleton(TheOne)
t1 = TheOne(42)
print(t1.arg, id(t1))
# 42 43808640
# Since this time around TheOne already is wrapper_singleton, wrapped by functools.wraps,
# You have to access your class object through the __wrapped__ attribute
TheOne = singleton(TheOne.__wrapped__)
t2 = TheOne(21)
print(t2.arg, id(t2))
# 21 43808920