Зачем тебе «я». в Python ссылаться на переменные экземпляра?

13

Я программировал на нескольких языках, таких как Java, Ruby, Haskell и Python. Мне приходится переключаться между многими языками в день из-за разных проектов, над которыми я работаю. Теперь проблема в том, что я часто забываю написать, так selfкак первый параметр в определениях функций в Python - это вызов методов для одного и того же объекта.

Тем не менее, я весьма удивлен таким подходом Python. По сути, мы должны набрать больше, чтобы добиться цели, в таких языках, как Java и Ruby, все делается просто, автоматически ссылаясь на переменные в текущем объекте.

Мой вопрос: зачем это selfнужно? Это просто выбор стиля, или есть причина, почему Python не может позволить вам опустить selfто, что Java и C ++ позволяют вам опустить this?

Вивек
источник
рекомендуемое чтение: в чем проблема с «за» и «против»?
комнат
1
@gnat теперь только профессионалы, и, если серьезно, это хороший вопрос, который беспокоит меня уже несколько дней, пожалуйста, не убивайте его, отказавшись от голосования.
Вивек
2
Этот вопрос более чем подробно освещен в stackoverflow.com/questions/2709821/… .
Дэвид Арно
Насколько я понимаю, это основано на C-стиле передачи указателя на структуру в качестве первого аргумента.
Dannnno
Запись @staticmethodперед объявлением метода подавляет ошибку (только для информации и также не рекомендуется)
Yash

Ответы:

23

1) Почему selfтребуется в качестве явного параметра в сигнатурах метода?

Потому что методы являются функциями и foo.bar(baz)просто синтаксическим сахаром для bar(foo, baz). Классы - это просто словари, в которых некоторые значения являются функциями. (Конструкторы также являются просто функциями, поэтому Python не нужен new). Вы можете сказать, что Python явно указывает, что объекты создаются из более простых компонентов. Это в соответствии с «явным лучше, чем неявным» -философия.

Напротив, в Java объекты действительно волшебны и не могут быть сведены к более простым компонентам в языке. В Java (по крайней мере, до Java 8) функция всегда является методом, принадлежащим объекту, и это владение не может быть изменено из-за статической природы языка. Поэтому нет никакой двусмысленности в отношении того, что thisотносится к этому, поэтому имеет смысл определить его неявным образом.

JavaScript - это пример языка, который неявно thisпохож на Java, но где функции могут существовать отдельно от объектов, как в Python. Это приводит к большим путаницы о том , что thisотносится к , когда функции передаются вокруг и называются в различных контекстах. Многие инстинктивно думают, что thisдолжны ссылаться на некоторое внутреннее свойство функции, в то время как оно на самом деле чисто определяется способом вызова функции. Я считаю, что наличие thisв качестве явного параметра, такого как в Python, сделает это намного менее запутанным.

Некоторые другие преимущества явного self-параметра:

  • Декораторы - это просто функции, которые обертывают другие функции. Поскольку методы - это просто функции, декораторы так же хорошо работают с методами. Если бы было какое-то неявное «я», декораторы не работали бы прозрачно с методами.

  • Методы класса и статические методы не принимают параметр экземпляра. Методы класса принимают класс в качестве первого аргумента (как правило, называется cls). Явные selfили clsпараметры делают намного более понятным, что происходит и к чему у вас есть доступ в методе.

2) Почему переменные экземпляров всегда должны быть квалифицированы как " self.?

В Java вам не нужно ставить переменные-члены перед " this.", но в Python " self." всегда требуется. Причина в том, что Python не имеет явного синтаксиса для объявления переменных, поэтому нет никакого способа узнать, x = 7предполагается ли объявить новую локальную переменную или назначить переменную-член. Указание self.решает эту двусмысленность.

JacquesB
источник
Неявная ссылка на переменную-член ( self.как, например, Java) принципиально несовместима с правилами области видимости, и когда вам нужно быть там явным, неявное отношение к параметру больше не имеет особого смысла.
Ян Худек
@JanHudec: Хорошо, точка. Я добавил это к ответу.
JacquesB
6

Существует довольно простая причина, по которой AFAIK на самом деле не затрагивался ни в межсайтовом дубликате, ни здесь: Python начинался как процедурный язык. Это было основано на ABC, также процедурном языке.

Объектно-ориентация была добавлена ​​позже, и когда она была добавлена, Гвидо ван Россум хотел добавить минимально возможное количество возможностей, чтобы сделать дизайн Python простым. В Python уже есть dicts и функции, так зачем добавлять что-то совершенно новое в язык, когда объект может быть просто dictиз слотов, а класс может просто быть dictиз функций? Метод можно интерпретировать как частично примененную функцию, которая закрывается по одному выделенному аргументу. И именно так методы реализуются в Python: это не так. Это просто функции, которые получают дополнительный выдающийся аргумент.

Йорг Миттаг
источник
Я считаю, что Python поддерживал OO и имел классы и наследование от самой первой выпущенной версии. По крайней мере, так говорит мне Википедия. Но процесс Ван Россумса в первоначальной разработке языка мог бы быть таким, как вы описали.
JacquesB
Спасибо за ссылку, это действительно интересное чтение.
JacquesB
2

Вот мои выводы, основанные на приведенных выше ответах и ​​прочтении собственного бессвязного Гвидо по этой теме:

Большая идея

Функции являются важными строительными блоками в Python (или мы должны сказать, единственный), на самом деле мы эмулируем ООП с помощью функций.

Учитывая, что класс - это не что иное, как словарь функций, следовательно, мы можем присоединить любую функцию к любому классу во время выполнения. По сути, из-за этой необходимости перебрасывать функции во время выполнения мы можем делать такие вещи, как Monkey Patching . Здесь selfпараметр, поддерживающий параметрический полиморфизм.

Вивек
источник
1
Ответы на самостоятельные вопросы приветствуются, если ваш ответ является качественным ответом. Когда я сравниваю ваш ответ здесь с другими ответами, мне остается удивляться, почему вы почувствовали, что вам нужно добавить это. Другие ответы углубляются и добавляют больше деталей, чем ваш ответ.
1
@ GlenH7 ответ был только для моей справки, потому что каждый раз, когда я не могу прийти и прочитать ответ каждого снова и снова. Что касается качества, скажите мне, если какая-то информация вводит в заблуждение. В любом случае я обычно жду 2-3 дня, чтобы принять любой ответ.
Вивек
Вниз голосование становится дешевой валютой, и все здесь тратят его обеими руками, не зная его значения. Понимаете ли вы, что если кто-то придет сюда, посмотрите, как проголосовали за этот ответ, что он ошибся!
Вивек