Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Магические методы

Что мне никогда не нравилось в Пайтоне, так это «магические» методы и свойства. Сейчас их существует за сотню:

bolk@Bolk ~  $ wget -O- http://docs.python.org/reference/datamodel.html 2>&- | egrep -o '__(\w+)__' | sort -u | wc -l
     108

Я, даже если очень постараюсь, вряд ли вспомню хотя бы половину. Всё «магическое» в Пайтоне начинается и заканчивается двумя подчёркиваниями, например, если сменить знак у объекта (сделать „-something“), то Пайтон попытается вызвать магический метод «__neg__». В более распространнённом ПХП всё примерно так же, но «магических» методов сильно меньше, их я уже помню на память все, но и возможности гораздо уже.

Запомнить все эти методы, наверное, реально при помощи тщательной зубрёжки, но сделать это естетственно, во время изучения языка, нереально, по моему мнению. Причина — неинтуитивность. Я давно высказывался на тему, почему хотя бы не расширить синтаксис и некоторые методы не разрешить называть как операции, то есть «/», «+», «[]» и так далее, смутно вспоминая, что в Си++, кажется, так и сделано.

Оказывается, так в точности сделано в языке «Скала»:

trait Ord{
    def < (that:Any):Boolean
    def<=(that:Any):Boolean = (this < that) || (this == that)
    def> (that:Any):Boolean = !(this <= that)
    def>=(that:Any):Boolean = !(this < that)
}

Это гораздо проще выучить, изучая язык, чем «__lt__», «__le__», «__gt__», «__ge__» (впрочем, когда перечисляешь в ряд несколько конструкций, кажется что ничего страшного в этом нет, но надо держать в голове, что их больше сотни).

У некоторых методов название упрощать не нужно, например «__unicode__» (преобразование к юникодной строке) всё равно дёргается стоит вызвать unicode(something) или «__del__» (деструктор) вызывается, в частности, если сделать «del something» (если ссылок больше нет). Они уже содержат название операции, просто оно буквенное. Есть методы, которые вряд ли вообще можно как-то проще назвать, например «__new__» и «__init__» — названия конструкторов для «новых» и «старых» объектов Пайтона.

Наверняка есть часть, которую понятнее не назовёшь. На ум сразу приходит метод «__hash__», думаю есть и ещё.

Но, бо́льшую часть, мне бы хотелось именовать как-то понятнее. Причём, вполне можно предложить синтаксис для левостоящих и правостоящих объектов, что-то вроде «def self+» и «def +self».

16 комментариев
Александр Кунташов (kuntashov.moikrug.ru) 2012

В Ruby так и сделано, и это действительно интуитивно понятнее.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для kuntashov.moikrug.ru:

Я почему-то подозревал, что в Руби так же. То ли где-то видел и в памяти отложилось, то ли это какое-то ожидание интуитивное от языка. Поискал утром в Википедии, не увидел подходящих примеров, не стал глубже смотреть.

Александр Кунташов (kuntashov.moikrug.ru) 2012

Комментарий для Евгения Степанищева:

Ключевые слова: ruby operator expressions.
Вот здесь коротко: http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html#s1

pan Ramon (rembish.livejournal.com) 2012

__new__ всё же не совсем конструктор объекта, это скорее «конструктор» мета-класса, т. е. того инстанцией чего будет текущий объект. В сравнении __new__ возвращает инстанцию класса, а __init__ уже с ней работает и не требует возврата.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для rembish.livejournal.com:

В данном контексте это лишняя подробность.

egorinsk 2012

Это еще что, вот в Хаскелле, говорят, можно вообще свои операторы вроде +++ придумывать. Хотя перегрузка операций для не-чисел — очень спорная вещь, так как если смотреть на код, непонятно с ходу, какой именно метод там вызывается.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для egorinsk:

Это просто другая запись для вызова какого-то метода. Синтаксический сахар. Когда я вижу object.something() я тоже не знаю что реализует something, могу только догадываться по названию. С этой точки зрения obj1+obj2 ничем не хуже (скорее лучше), чем obj1.add(obj2).

hshhhhh (hshhhhh.name) 2012

А нельзя запилить какой файл с аллиасами?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для hshhhhh.name:

М? Что?

hshhhhh (hshhhhh.name) 2012

Комментарий для Евгения Степанищева:

ну, в смысле, что-нибудь типа файла:
function __>__ () {
return __gt__();
}

Евгений Степанищев (bolknote.ru) 2012

Комментарий для hshhhhh.name:

Нет, так работать не будет.

Во-первых, будет ошибка синтаксиса (имена функций и методов не могут в языке содержать такие символы).
Во-вторых, это тут функции, а надо методы.

Fulcrum (fulc.ru) 2012

Это гораздо проще выучить, изучая язык, чем «__lt__», «__le__», «__gt__», «__ge__»

Во время изучения языка вся эта сотня магических методов не нужна, поэтому и приходится учить последовательно понемногу. И, кажется, перечисленные методы вполне интуитивны, чтобы их запомнить, когда дело доходит до них.

Еще есть синтаксическая проблема: поскольку все функции являются объектами, название метода (функции) не должно ломать синтаксис не только в его определении, но и само по себе. А с точки зрения синтаксиса, __<__, +self и т. п. не могут являться атомарными токенами. Если разрешить называть метод «<», но запретить вызывать его как <(obj1, obj2), на мой взгляд, проигрыш в интуитивности будет гораздо больше.

Ну и ты сам говоришь, что магических методов больше сотни, а переименовать предлагаешь лишь малую часть, так что это не решит проблему.

Евгений Степанищев (bolknote.ru) 2012

Комментарий для fulc.ru:

И, кажется, перечисленные методы вполне интуитивны, чтобы их запомнить, когда дело доходит до них.

Я просмотрел эту сотню бегло. Знаешь, по одиночке они более-менее интуитивны, вместе — нет.

А с точки зрения синтаксиса, __<__, +self и т. п. не могут являться атомарными токенами.

И не должны. Атомарным токеном должно являеться «<», «+» и прочие названия (в этом контексте) методов. «+self» тут два токена — название метода и название переменной, куда текущий экземпляр кладётся.

Если разрешить называть метод „<“, но запретить вызывать его как <(obj1, obj2), на мой взгляд, проигрыш в интуитивности будет гораздо больше.

В Пайтоне уже есть место, которое работает так же, ничего живём. Даже специальный модуль есть — operator.

Ну и ты сам говоришь, что магических методов больше сотни, а переименовать предлагаешь лишь малую часть, так что это не решит проблему.

Переименовать предлагаю большую часть. Большая часть относится как раз к операциям.

desh 2012

Комментарий для egorinsk:

В хаскеле ещё интереснее — любую функцию можно вызывать инфиксно. Т. е. можно «foo a b», а можно «a ’foo’ b» :) и наоборот: «(+) a b». Кавычки только там другие,в телефоне нету:)

Fulcrum (fulc.ru) 2012

Комментарий для Евгения Степанищева:

Если разрешить называть метод „<“, но запретить вызывать его как <(obj1, obj2), на мой взгляд, проигрыш в интуитивности будет гораздо больше.

В Пайтоне уже есть место, которое работает так же, ничего живём.

Это какое?

Евгений Степанищев (bolknote.ru) 2012

Комментарий для fulc.ru:

Модуль operator.