Почему Python использует два подчеркивания для определенных вещей?

Я довольно плохо знаком с реальными языками программирования, и Python - мой первый. Я немного разбираюсь в Linux, достаточно, чтобы получить летнюю работу с ним (я еще учусь в средней школе), и на работе у меня много свободного времени, которое я использую для изучения Python.

Хотя, одна вещь меня заводит. Что именно отличается в Python, когда у вас есть такие выражения, как

x.__add__(y) <==> x+y
x.__getattribute__('foo') <==> x.foo

Я знаю, что делают методы и все такое, и я получаю то, что они делают, но мой вопрос: чем эти методы подчеркивания с двойным подчеркиванием отличаются от их простых на вид эквивалентов?

PS Я не возражаю против того, чтобы мне читали лекции по истории программирования, на самом деле, я нахожу это очень полезным знать:) Если это в основном исторические аспекты Python, не стесняйтесь начинать бродить.

7 ответов

Решение

Что ж, сила для программиста хорошая, поэтому должен быть способ настроить поведение. Как перегрузка оператора (__add__, __div__, __ge__,...), атрибут доступа (__getattribute__, __getattr__ (эти два разные), __delattr__,...) и т. д. Во многих случаях, подобно операторам, обычный синтаксис отображает 1:1 в соответствующий метод. В других случаях существует специальная процедура, которая в определенный момент включает вызов соответствующего метода - например, __getattr__ вызывается только если объект не имеет запрошенного атрибута и __getattribute__ не реализован или не вызван AttributeError. И некоторые из них - действительно продвинутые темы, которые помогают вам проникнуть в суть объектной системы и редко нужны. Так что не нужно изучать их все, просто обратитесь к справке, когда вам нужно / хотите знать. Говоря о ссылке, вот она.

Вот создатель Python, объясняющий это:

... вместо того чтобы разрабатывать новый синтаксис для специальных видов методов класса (таких как инициализаторы и деструкторы), я решил, что эти функции могут быть обработаны, просто требуя от пользователя реализации методов со специальными именами, такими как __init__, __del__, и так далее. Это соглашение об именах взято из C, где идентификаторы, начинающиеся с подчеркивания, зарезервированы компилятором и часто имеют особое значение (например, макросы, такие как __FILE__ в препроцессоре C).

...

Я также использовал эту технику, чтобы позволить пользовательским классам переопределить поведение операторов Python. Как отмечалось ранее, Python реализован на C и использует таблицы указателей функций для реализации различных возможностей встроенных объектов (например, "get attribute", "add" и "call"). Чтобы эти возможности могли быть определены в пользовательских классах, я сопоставил различные указатели функций с именами специальных методов, такими как __getattr__, __add__, а также __call__, Существует прямое соответствие между этими именами и таблицами указателей функций, которые необходимо определить при реализации новых объектов Python в C.

Когда вы запускаете метод с двумя подчеркиваниями (и без завершающих подчеркиваний), применяются правила искажения имен в Python. Это способ свободно моделировать private Ключевое слово из других ОО языков, таких как C++ и Java. (Несмотря на это, метод технически все еще не является частным в том смысле, что методы Java и C++ являются частными, но его "сложнее получить" извне экземпляра.)

Методы с двумя начальными и двумя завершающими подчеркиваниями считаются "встроенными" методами, то есть они используются интерпретатором и, как правило, являются конкретными реализациями перегруженных операторов или других встроенных функций.

Они используются для указания того, что интерпретатор Python должен использовать их в определенных ситуациях.

Например, __add__ функция позволяет + оператор для работы на пользовательских классах. В противном случае вы получите какую-то неопределенную ошибку при попытке добавить.

С исторической точки зрения начальные подчеркивания часто использовались в качестве метода для указания программисту, что имена следует рассматривать как внутренние для пакета / модуля / библиотеки, который их определяет. В языках, которые не обеспечивают хорошую поддержку частных пространств имен, использование подчеркивания является соглашением для эмуляции этого. В Python, когда вы определяете метод с именем '__foo__', программист по обслуживанию знает по имени, что происходит нечто особенное, чего не происходит с методом с именем 'foo'. Если бы Python выбрал использование "add" в качестве внутреннего метода для перегрузки "+", то вы никогда не могли бы иметь класс с методом "add", не вызывая большой путаницы. Подчеркивание служит сигналом того, что случится какое-то волшебство.

Ряд других вопросов теперь помечены как дубликаты этого вопроса, и по крайней мере два из них задают вопрос, что либо __spam__ Вызываются методы или то, что называется соглашением, и ни один из существующих ответов не покрывает это, поэтому:

Там на самом деле нет официального названия либо.

Многие разработчики неофициально называют их "более грубыми методами", что означает "двойной UNDERscore".

Некоторые люди используют термин "магические методы", но это несколько двусмысленно в смысле "более сложные методы", "специальные методы" (см. Ниже) или что-то среднее между ними.


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

  • Атрибут, который предоставляется самим интерпретатором или его встроенным кодом, например __name__ на функции.
  • Атрибут, который является частью протокола, реализованного самим интерпретатором, например __add__ для + оператор или __getitem__ для индексации и нарезки.
  • Атрибут, который интерпретатору разрешено искать специально, игнорируя экземпляр и переходя прямо к классу, например __add__ снова.

Большинство специальных атрибутов - это методы, но не все (например, __name__ нет). И большинство из них используют соглашение о "дунду", но не все (например, next метод на итераторах в Python 2.x).

Между тем, большинство более сложных методов - это специальные атрибуты, но не все, в частности, stdlib или внешние библиотеки нередко хотят определять свои собственные протоколы, которые работают одинаково, например, pickle протокол.

[Предположение] Python находился под влиянием Algol68, возможно, Гвидо использовал Algol68 в университете Амстердама, где у Algol68 есть аналогичный " режим стреппинг", называемый "стриппинг цитат". В Algol68 операторы, типы и ключевые слова могут появляться в другом шрифте (обычно **полужирный** или __underlined__), в файлах исходного кода эта гарнитура достигается с помощью кавычек, например, "abs" (цитирование аналогично цитированию в " wikitext").)

Algol68 ⇒ Python (Операторы сопоставлены с функциями-членами)

  • 'и' ⇒ __and__
  • 'или' ⇒ __or__
  • "не" ⇒ не
  • 'entier' ⇒ __trunc__
  • 'шл' ⇒ __lshift__
  • 'shr' ⇒ __rshift__
  • 'upb' ⇒ __sizeof__
  • "длинный" ⇒ __long__
  • 'int' ⇒ __int__
  • 'реальный' ⇒ __float__
  • 'формат' ⇒ __format__
  • 'repr' ⇒ __repr__
  • 'abs' ⇒ __abs__
  • "минус" ⇒ __neg__
  • "минус" ⇒ __sub__
  • "плюс" ⇒ __add__
  • "времена" ⇒ __mul__
  • 'мод' ⇒ __mod__
  • 'div' ⇒ __truediv__
  • "над" ⇒ __div__
  • 'вверх' ⇒ __pow__
  • 'im' ⇒ имаг
  • '⇒ реальный
  • 'con' ⇒ сопряженный

В Algol68 их называли жирными именами, например, abs, но "под-под-abs" __abs__ в python.

Мои 2 цента: ¢ Так что иногда - как призрак - когда вы вырезаете и вставляете классы python в вики, вы волшебным образом перевоплощаете смелые ключевые слова Algol68. ¢

Другие вопросы по тегам