В большинстве известных объектно-ориентированных языков выражение типа SomeClass(arg1, arg2)
выделяет новый экземпляр, инициализирует атрибуты экземпляра, а затем возвращает его.
В большинстве известных объектно-ориентированных языков часть «инициализировать атрибуты экземпляра» может быть настроена для каждого класса путем определения конструктора, который в основном представляет собой просто блок кода, который работает с новым экземпляром (используя аргументы, предоставленные выражению конструктора), чтобы установить любые желаемые начальные условия. В Python это соответствует методу __init__
класса.
__new__
Python - это не что иное, как аналогичная индивидуальная настройка для каждого класса части «выделить новый экземпляр». Это, конечно, позволяет вам делать необычные вещи, например, возвращать существующий экземпляр, а не выделять новый. Таким образом, в Python мы не должны думать об этой части как о обязательно связанной с распределением; все, что нам нужно, это чтобы __new__
откуда-то придумал подходящий экземпляр.
Но это по-прежнему только половина работы, и система Python не может знать, что иногда вы хотите выполнить вторую половину работы (__init__
) впоследствии, а иногда нет. Если вы хотите такого поведения, вы должны заявить об этом прямо.
Часто вы можете провести рефакторинг так, чтобы вам нужно было только __new__
, или около того, что вам не нужно __new__
, или чтобы __init__
вел себя по-другому на уже инициализированном объекте. Но если вы действительно хотите, Python действительно позволяет вам переопределить «задание», так что SomeClass(arg1, arg2)
не обязательно вызывает __new__
, за которым следует __init__
. Для этого вам нужно создать метакласс и определить его __call__
метод.
Метакласс - это просто класс класса. А метод __call__
класса управляет тем, что происходит, когда вы вызываете экземпляры класса. Итак, метод метакласса '__call__
управляет тем, что происходит, когда вы вызываете класс; то есть позволяет переопределить механизм создания экземпляров от начала до конца. Это уровень, на котором вы можете наиболее элегантно реализовать совершенно нестандартный процесс создания экземпляра, такой как шаблон singleton. Фактически, с менее чем 10 строками кода вы можете реализовать Singleton
метакласс, который тогда даже не требует, чтобы вы использовали __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
Однако это, вероятно, более глубокая магия, чем действительно оправдано в данной ситуации!
person
Ben
schedule
29.12.2011