Когда (и почему) был представлен Python `__new __ ()`? - PullRequest
14 голосов
/ 03 мая 2019

Когда (и почему) была введена функция 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 , но он не появляется в whathsnew любой из версий Python 2.Первый коммит , который ввел __new__ (Слияние descr-branch обратно в trunk.), Который я смог найти, относится к 2001 году, но сообщение «back to trunk» является признаком того, что что-то было раньше. PEP 252 (создание типов, более похожих на классы) и PEP 253 (подтипы встроенных типов) из нескольких месяцев ранее, кажется, имеют значение.

Изучениео введении __new__ мы узнаем больше о том, почему Python такой, какой он есть.


Редактировать для пояснения:

Кажется, что class.__new__ дублирует функциональность, которая уже естьпредоставлено metaclass.__call__.Кажется неуместным добавлять метод только для лучшей репликации существующих функций.

__new__ - это один из немногих методов класса, которые вы получаете из коробки (то есть с cls в качестве первогоаргумент), тем самым вводя сложность, которой не было раньше.Если класс является первым аргументом функции, то можно утверждать, что функция должна быть обычным методом метакласса.Но этот метод уже существовал: __call__().Я чувствую, что что-то упустил.

Должен быть один - и желательно только один - очевидный способ сделать это.

Ответы [ 2 ]

6 голосов
/ 03 мая 2019

Пост в блоге The Inside Story on New-Style Classes (из метко названного http://python-history.blogspot.com), написанного Guido van Rossum (BDFL Python), предоставляет некоторую полезную информацию по этому вопросу.

Некоторые соответствующие цитаты:

В классах нового стиля появился новый метод класса __new__(), который позволяет автор класса настраивает, как создаются новые экземпляры класса. От переопределение __new__() автор класса может реализовать шаблоны, такие как Singleton Pattern, возвращает ранее созданный экземпляр (например, из свободный список) или для возврата экземпляра другого класса (например, подкласс). Однако использование __new__ имеет и другие важные Приложения. Например, в модуле рассола __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 голосов
/ 03 мая 2019

Я не буду объяснять историю __new__ здесь, потому что я использовал Python только с 2005 года, поэтому после того, как он был введен в язык.Но здесь есть логическое обоснование.

Метод конфигурации normal для нового объекта - это метод __init__ его класса.Объект уже был создан (обычно через косвенный вызов object.__new__), а метод просто инициализирует его.Проще говоря, если у вас действительно не изменяемый объект, это слишком поздно.

В этом случае Pythonic использует метод __new__, который создает и возвращает новый объект.Приятно отметить, что он все еще включен в определение класса и не требует определенного метакласса.Стандартная документация гласит:

new () предназначен главным образом для того, чтобы подклассы неизменяемых типов (таких как int, str или tuple) могли настраивать создание экземпляров.Он также обычно переопределяется в пользовательских метаклассах для настройки создания класса.

Определение метода __call__ для метакласса действительно разрешено, но, по-моему, не является Pythonic, потому что __new__ должно быть достаточно.Кроме того, __init__, __new__ и метаклассы каждый копают глубже внутри внутреннего механизма Python.Таким образом, правило должно быть , не используйте __new__, если достаточно __init__, и не используйте метаклассы, если __new__ достаточно .

...