Когда (и почему) был представлен Python '__new __()'?
Когда (и почему) была введена функция Python __new__()
?
Есть три шага в создании экземпляра класса, например, MyClass()
:
-
MyClass.__call__()
вызывается. Этот метод должен быть определен в метаклассе MyClass
. -
MyClass.__new__()
вызывается (__call__
). Определено на самом MyClass
. Это создает экземпляр. -
MyClass.__init__()
вызывается (также __call__
). Это инициализирует экземпляр.
На создание экземпляра может повлиять либо перегрузка __call__
либо __new__
. Обычно нет особых причин перегружать __call__
вместо __new__
(например, использовать метод __call__ метакласса вместо __new__?).
У нас есть старый код (все еще работающий!), Где __call__
перегружен. Причина была в том, что __new__
не было доступно в то время. Поэтому я попытался узнать больше об истории как Python, так и нашего кода, но я не мог понять, когда был введен __new__
.
__new__
появляется в документации для Python 2.4, а не в документации для Python 2.3, но не появляется ни в одной из версий Python 2. Первый коммит, в котором было введено __new__
(слияние descr-branch обратно в trunk.), Который я смог найти, был сделан в 2001 году, но сообщение "back to trunk" указывает на то, что что-то было раньше. PEP 252 (создание типов, более похожих на классы) и PEP 253 (создание встроенных типов подтипов) нескольких месяцев назад представляются актуальными.
Если вы __new__
больше о введении __new__
вы __new__
больше о том, почему Python такой, какой он есть.
Изменить для уточнения:
Похоже, что class.__new__
дублирует функциональность, которая уже предоставлена metaclass.__call__
. Кажется неуместным добавлять метод только для лучшей репликации существующих функций.
__new__
- это один из немногих методов класса, которые вы получаете из коробки (то есть с cls
качестве первого аргумента), тем самым привнося сложность, которой раньше не было. Если класс является первым аргументом функции, то можно утверждать, что функция должна быть обычным методом метакласса. Но этот метод уже существует: __call__()
. Я чувствую, что что-то упустил.
Должен быть one-- и, предпочтительно, только один --obvious способ сделать это.
Ответы
Ответ 1
Сообщение в блоге The Inside Story on New-Style Classes
(из метко названного http://python-history.blogspot.com
), написанное Guido van Rossum
(Python BDFL), предоставляет некоторую хорошую информацию по этому вопросу.
Некоторые соответствующие цитаты:
В классах нового стиля появился новый метод класса __new__()
который позволяет автору класса настраивать создание новых экземпляров класса. Переопределив __new__()
автор класса может реализовать шаблоны, такие как шаблон Singleton, вернуть ранее созданный экземпляр (например, из свободного списка) или вернуть экземпляр другого класса (например, подкласс). Однако использование __new__
имеет и другие важные приложения. Например, в модуле pickle __new__
используется для создания экземпляров при десериализации объектов. В этом случае экземпляры создаются, но метод __init__
не вызывается.
Другое использование __new__
- это помощь в создании подклассов неизменяемых типов. В силу своей неизменности объекты такого типа не могут быть инициализированы стандартным методом __init__()
. Вместо этого любой вид специальной инициализации должен выполняться при создании объекта; например, если класс хочет изменить значение, хранящееся в неизменяемом объекте, метод __new__
может сделать это, передав измененное значение методу базового класса __new__
.
Вы можете прочитать весь пост для получения дополнительной информации на эту тему.
Другой пост о New-style Classes
который был написан вместе с цитируемым выше постом, содержит дополнительную информацию.
Редактировать:
В ответ на редактирование OP и цитату из Zen of Python я бы сказал это.
Zen of Python был написан не создателем языка, а Тимом Питерсом и был опубликован только 19 августа 2004 года. Мы должны учитывать тот факт, что __new__
появляется только в документации Python 2.4 (которая была выпущена в ноябре). 30, 2004), и этот конкретный принцип (или афоризм) даже не существовал публично, когда __new__
был введен в язык.
Даже если такой документ руководящих принципов ранее существовал в неофициальном порядке, я не думаю, что автор предполагал, что они будут неправильно истолкованы как проектный документ для всего языка и экосистемы.
Ответ 2
Я не буду объяснять историю __new__
здесь, потому что я использовал Python только с 2005 года, поэтому после того, как он был введен в язык. Но вот обоснование этого.
Обычный метод конфигурации для нового объекта - это метод __init__
его класса. Объект уже создан (обычно через косвенный вызов object.__new__
), и метод просто его инициализирует. Проще говоря, если у вас действительно не изменяемый объект, это слишком поздно.
В этом случае __new__
- это метод __new__
, который создает и возвращает новый объект. Приятно отметить, что он все еще включен в определение класса и не требует определенного метакласса. Стандартная документация гласит:
new() предназначен главным образом для того, чтобы позволить подклассам неизменяемых типов (таких как int, str или tuple) настраивать создание экземпляров. Он также обычно переопределяется в пользовательских метаклассах для настройки создания классов.
Определение метода __call__
в метаклассе действительно разрешено, но IMHO не Pythonic, потому что __new__
должно быть достаточно. Кроме того, __init__
, __new__
и метаклассы каждый копают глубже во внутреннем механизме Python. Так что правило должно быть не использовать __new__
если __init__
достаточно, и не использовать метаклассы, если __new__
достаточно.
Ответ 3
Метод __new__
позволяет создавать одноэлементные объекты, отслеживать созданные объекты и прочее. У вызываемых классов тоже много вариантов использования, наиболее распространенными из которых являются декораторы.