В большинстве известных языков OO выражение like SomeClass(arg1, arg2)
будет выделять новый экземпляр, инициализировать атрибуты экземпляра и затем возвращать его.
В большинстве известных ОО-языков часть «инициализировать атрибуты экземпляра» может быть настроена для каждого класса путем определения конструктора , который по сути является просто блоком кода, который работает с новым экземпляром (используя аргументы, предоставленные выражению конструктора). ) для установки любых начальных условий. В Python это соответствует __init__
методу класса .
Python - __new__
это не что иное, как похожая настройка для каждого класса для части «выделите новый экземпляр». Это, конечно, позволяет вам делать необычные вещи, такие как возврат существующего экземпляра, а не выделение нового. Так что в Python мы не должны думать об этой части как об обязательном распределении; все, что нам нужно, - это __new__
найти подходящий экземпляр откуда-то.
Но это все еще только половина работы, и у системы Python нет возможности узнать, что иногда вы хотите запустить другую половину задания ( __init__
) впоследствии, а иногда нет. Если вы хотите такое поведение, вы должны сказать об этом явно.
Часто вы можете __new__
выполнить рефакторинг так, чтобы вам было нужно , или вам не нужно __new__
, или так, что он __init__
ведет себя по-другому на уже инициализированном объекте. Но если вы действительно хотите, Python действительно позволяет вам переопределить «работу», так что SomeClass(arg1, arg2)
это не обязательно вызов, __new__
а затем __init__
. Для этого вам нужно создать метакласс и определить его __call__
метод.
Метакласс - это просто класс класса. И __call__
метод класса контролирует, что происходит, когда вы вызываете экземпляры класса. Таким образом , метод метакласса__call__
контролирует, что происходит, когда вы вызываете класс; то есть позволяет переопределить механизм создания экземпляра от начала до конца . Это уровень, на котором вы можете наиболее элегантно реализовать совершенно нестандартный процесс создания экземпляра, такой как шаблон синглтона. На самом деле, с менее чем 10 строк кода вы можете реализовать Singleton
метакласса , что тогда даже не потребует от вас futz с __new__
на всех , и может превратить любое иное-нормальный класс в синглтон, просто добавляя __metaclass__ = Singleton
!
class Singleton(type):
def __init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
Однако это, вероятно, более глубокая магия, чем на самом деле оправдано для этой ситуации!