Почему Python использует 'волшебные методы'?

Я играл вокруг с Python недавно, и одной вещью, которую я нахожу немного нечетным, является широкое применение 'волшебных методов', например, сделать его длину доступной, объект реализует метод, def __len__(self), и затем это называют, когда Вы пишете len(obj).

Я просто задавался вопросом, почему объекты просто не определяют a len(self) методу и назвали его непосредственно как члена объекта, например. obj.len()? Я уверен, что должны быть серьезные основания для Python, делающего его способ, которым это делает, но как новичок я не разработал то, что они все же.

97
задан Peter Mortensen 25 August 2018 в 21:52
поделиться

5 ответов

AFAIK, len является особенным в этом отношении и имеет исторические корни.

Вот цитата из FAQ :

Почему Python использует методы для некоторых функций (например, list.index ()), а - для других ( например, len (list))?

Основная причина - история. Функции использовались для тех операций, которые были общими для группы типов и , которые предназначались для работы даже с объектами, не имеющими методов в все (например, кортежи). Также удобно иметь функцию, которую можно легко применить к аморфной коллекции объектов, когда вы используете функциональные возможности Python (map ( ), apply () и др.).

На самом деле реализация len (), max (), min () в качестве встроенной функции на самом деле меньше кода, чем реализация их как методов для каждого тип. Можно спорить об отдельных случаях, но это часть Python, и сейчас слишком вносить такие фундаментальные изменения . Функции должны оставаться, чтобы избежать серьезных сбоев кода.

Другие «магические методы» (на самом деле называемые специальным методом в фольклоре Python) имеют много смысла, и аналогичные функции существуют и в других языках. В основном они используются для кода, который вызывается неявно при использовании специального синтаксиса.

Например:

  • перегруженные операторы (существуют в C ++ и др.)
  • конструктор / деструктор
  • хуки для доступа к атрибутам
  • инструменты для метапрограммирования

и так далее ...

{ {1}}
63
ответ дан 24 November 2019 в 05:30
поделиться

На самом деле это не «волшебные имена». Это просто интерфейс, который объект должен реализовать для предоставления данной услуги. В этом смысле они не более волшебны, чем любое предопределенное определение интерфейса, которое вам нужно переопределить.

4
ответ дан 24 November 2019 в 05:30
поделиться

К двум вышеупомянутым постам добавить особо нечего, но все "волшебные" функции на самом деле вовсе не волшебные. Они являются частью модуля __ builtins__, который неявно / автоматически импортируется при запуске интерпретатора. То есть: [

from __builtins__ import *

] происходит каждый раз перед запуском вашей программы.

Я всегда думал, что было бы правильнее, если бы Python делал это только для интерактивной оболочки и требовал сценариев для импорта различных частей из необходимых им встроенных функций. Также, вероятно, другая обработка __ main__ была бы хороша в оболочках против интерактивных. В любом случае, проверьте все функции и посмотрите, как это выглядит без них:

dir (__builtins__)
...
del __builtins__
0
ответ дан 24 November 2019 в 05:30
поделиться

Некоторые из этих функций делают больше, чем может реализовать один метод (без абстрактных методов в суперклассе). Например, 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 __ () .

9
ответ дан 24 November 2019 в 05:30
поделиться

Из дзен Python:

In лицо двусмысленности, откажитесь от соблазна угадать.
Должен быть один - а желательно только один - очевидный способ сделать это.

Это одна из причин - с пользовательскими методами разработчики могут выбрать другое имя метода, например getLength () , length () , getlength. () или что-то еще. Python обеспечивает строгое именование, чтобы можно было использовать общую функцию len () .

Все операции, общие для многих типов объектов, помещаются в магические методы, например __ nonzero __ , __ len __ или __ repr __ . Однако в большинстве случаев они необязательны.

Перегрузка операторов также выполняется с помощью магических методов (например, __ le __ ), поэтому имеет смысл использовать их и для других общих операций.

20
ответ дан 24 November 2019 в 05:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: