PythonFuck: разбор
Как я писал в конце прошлого года, есть такое развлечение — не используя
Получилась такая программа, работающая только из консоли интерпретатора и только под вторым «Пайтоном»:
_=(''<())+(''<());__=_**_**_
___='%'+('%'+`'±'`[_])%(__-_-_)
___*(_*_*_-_)%((
(__+_)*_*_,
`{_}`[_/_],
)+(`(''<'')`[_],)*_+\
(
__*_*_*_-__-_/_,
__*_+_/_,
))Пришло время разобрать как она работает. Я собирался сделать написать разбор через неделю после её написания, но заботы конца года не позволили.
С самого начала было очевидно, что в указанных ограничениях Пайтон не позволит вызвать
module, method = "__builtin__", "print"
vars(vars()[module])[method]("Hello")Есть варианты, но без использования букв — никак.
Так как в силу вышеизложенного функцию печати не вызовешь, пришлось довольствоваться выражением в консоли интерпретатора — там результат выводится на экран автоматически. В остальном, как будет видно ниже, удалось обойтись теми конструкциями, которые есть в языке.
Посмотрим в код. Первая строка:
_=(''<())+(''<());__=_**_**_Тут два разных выражения, разделённых точкой с запятой. В первом в скобках я дважды сравниваю строку и кортеж, получая два True. Второй Пайтон позволяет сравнивать разные встроенные типы, возвращая результат сравнения их названий, записанных как строки. Так как строка str меньше tuple, то результат — истина.
Два True в арифметической сумме дают двойку, неявно преобразовываясь к числу в этой операции. В принципе тут можно использовать унарный минус и тильду, но тогда мне это в голову не пришло:
_=-~(''<()) # число «2» можно получить и так тожеРезультат мы кладём в переменную с именем «подчёркивание». В той же строке мы получаем «16» возводя два в степень два в степени два, результат помещается в переменную «два подчёркивания».
Вторая строка:
___='%'+('%'+`'±'`[_])%(__-_-_)Тут используется символ «±», он
Этот символ вставлен внутрь конструкции «обратный апостроф», которая является во втором Пайтоне эквивалентом repr — функции, возвращающей строковое представление объекта, в данном случае это будет «'\\xc2\\xb1'». Нам отсюда нужен второй символ (нумерация с нуля) — «x». Цифра два для индекса у нас уже есть — в переменной _.
Дальше используется оператор «процент» — форматированный вывод. Полученное «x» используется как шаблон для «процента», чтобы преобразовать число в шестнадцатеричный вид. Из выражения __-_-_ (16−2−2) получаем «12» или, после преобразования, «c».
Вообще можно было обойтись без этого шага, получив эту же букву из строкового представления «±» («'\\xc2\\xb1'»), но в процессе продумывания я себе выписал ряд трюков и мне хотелось использовать их все.
В итоге, в переменную «три подчёркивания» попадает строка «%с», её мы будем использовать для оператора форматированного вывода («%»), чтобы получать символ по его коду.
Дальше символы получаются следующим образом:
(__+_)*_*_ # (16+2)*2*2 = 72, код символа «H», через шаблон «%c» получим отсюда букву
`{_}`[_/_] # первая часть даёт строку «set([2])», отсюда берём символ «e»
`(''<'')`[_]*_ # получаем строку «False», оттуда символ «l», удваиваем его умножением на два
__*_*_*_-__-_/_ # 16*2*2*2-16-2/2 = 111, код символа «о»
__*_+_/_ # 16*2+2/2 = 33, код символа «!»Не требующее преобразования оставляем как есть, а из кодов символы получаем шаблоном «%с». В результате складывается строка «Hello!».
Второй, а не третий Пайтон нужен, в основном,
Сладимый
Услышал от одного человека на днях «вода тут
Судя по словарю Даля, слово действительно синоним «сладкому», «солодковатому», хотя некоторые другие словари определяют его значение как «услащаемый», «подслащиваемый». То есть «сладимая вода» — это «сладкая» или «послащённая».
Добавлено позднее: в фейсбуке один из комментаторов написал, что слышал в устной речи «слатимая», через «т». Я тоже услышал это слово через «т», но такой вариант в словарях не нашёл, поэтому подумал, что послышалось.