Я играл вокруг с Python недавно, и одной вещью, которую я нахожу немного нечетным, является широкое применение 'волшебных методов', например, сделать его длину доступной, объект реализует метод, def __len__(self)
, и затем это называют, когда Вы пишете len(obj)
.
Я просто задавался вопросом, почему объекты просто не определяют a len(self)
методу и назвали его непосредственно как члена объекта, например. obj.len()
? Я уверен, что должны быть серьезные основания для Python, делающего его способ, которым это делает, но как новичок я не разработал то, что они все же.
AFAIK, len
является особенным в этом отношении и имеет исторические корни.
Вот цитата из FAQ :
Почему Python использует методы для некоторых функций (например, list.index ()), а - для других ( например, len (list))?
Основная причина - история. Функции использовались для тех операций, которые были общими для группы типов и , которые предназначались для работы даже с объектами, не имеющими методов в все (например, кортежи). Также удобно иметь функцию, которую можно легко применить к аморфной коллекции объектов, когда вы используете функциональные возможности Python (map ( ), apply () и др.).
На самом деле реализация len (), max (), min () в качестве встроенной функции на самом деле меньше кода, чем реализация их как методов для каждого тип. Можно спорить об отдельных случаях, но это часть Python, и сейчас слишком вносить такие фундаментальные изменения . Функции должны оставаться, чтобы избежать серьезных сбоев кода.
Другие «магические методы» (на самом деле называемые специальным методом в фольклоре Python) имеют много смысла, и аналогичные функции существуют и в других языках. В основном они используются для кода, который вызывается неявно при использовании специального синтаксиса.
Например:
и так далее ...
{ {1}}На самом деле это не «волшебные имена». Это просто интерфейс, который объект должен реализовать для предоставления данной услуги. В этом смысле они не более волшебны, чем любое предопределенное определение интерфейса, которое вам нужно переопределить.
К двум вышеупомянутым постам добавить особо нечего, но все "волшебные" функции на самом деле вовсе не волшебные. Они являются частью модуля __ builtins__, который неявно / автоматически импортируется при запуске интерпретатора. То есть: [
from __builtins__ import *
] происходит каждый раз перед запуском вашей программы.
Я всегда думал, что было бы правильнее, если бы Python делал это только для интерактивной оболочки и требовал сценариев для импорта различных частей из необходимых им встроенных функций. Также, вероятно, другая обработка __ main__ была бы хороша в оболочках против интерактивных. В любом случае, проверьте все функции и посмотрите, как это выглядит без них:
dir (__builtins__)
...
del __builtins__
Некоторые из этих функций делают больше, чем может реализовать один метод (без абстрактных методов в суперклассе). Например, bool ()
действует примерно так:
def bool(obj):
if hasattr(obj, '__nonzero__'):
return bool(obj.__nonzero__())
elif hasattr(obj, '__len__'):
if obj.__len__():
return True
else:
return False
return True
Вы также можете быть на 100% уверены, что bool ()
всегда будет возвращать True или False; если вы полагались на какой-то метод, вы не могли быть полностью уверены, что получите в ответ.
Некоторые другие функции, которые имеют относительно сложные реализации (более сложные, чем могут быть лежащие в основе магические методы): iter ()
и cmp ()
, а также все методы атрибутов ( getattr
, setattr
и delattr
). Такие вещи, как int
, также обращаются к магическим методам при выполнении принуждения (вы можете реализовать __ int __
), но выполняют двойную функцию как типы. len (obj)
на самом деле единственный случай, когда я не верю, что он когда-либо отличается от obj .__ len __ ()
.
Из дзен Python:
In лицо двусмысленности, откажитесь от соблазна угадать.
Должен быть один - а желательно только один - очевидный способ сделать это.
Это одна из причин - с пользовательскими методами разработчики могут выбрать другое имя метода, например getLength ()
, length ()
, getlength. ()
или что-то еще. Python обеспечивает строгое именование, чтобы можно было использовать общую функцию len ()
.
Все операции, общие для многих типов объектов, помещаются в магические методы, например __ nonzero __
, __ len __
или __ repr __
. Однако в большинстве случаев они необязательны.
Перегрузка операторов также выполняется с помощью магических методов (например, __ le __
), поэтому имеет смысл использовать их и для других общих операций.