27.11.2018       Выпуск 258 (26.11.2018 - 02.12.2018)       Статьи

Внутренности Python. Пасхалки

Привет! На хабре было довольно много статей про пасхалки питона, но вроде нигде не упоминалось про то, как все это устроено изнутри. Думаю, что будет интересно прежде всего начинающим питонистам. Об этом и пойдет речь под катом!

Читать>>




Экспериментальная функция:

Ниже вы видите текст статьи по ссылке. По нему можно быстро понять ссылка достойна прочтения или нет

Просим обратить внимание, что текст по ссылке и здесь может не совпадать.

Привет! На Хабре было довольно много статей про пасхалки питона, но вроде нигде не упоминалось про то, как все это устроено изнутри.

Думаю, что будет интересно прежде всего начинающим питонистам. Об этом и пойдет речь под катом!

Какая пасхалка питона первой приходит на ум?

Конечно, Zen of Python (import this)

Переходим в папку с исходниками Python или открываем

гитхаб

.

Вот его исходник:

Cырцы
s = """Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""

d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print("".join([d.get(c, c) for c in s]))

Ну как? Какая-то perlовая каша… Зачем нужно было заморачиваться с получением символа по коду? Непонятно.

Идем дальше. Ищем antigravity на гитхабе. Находим вот что:

image

Как видим, модуля нет.

А что это значит? Что пора попробовать выполнить скрипт configure, возможно он сгенерирует нужный файл. Выполняем ./configure в папке с исходниками Python.

Проверяем папку Lib и находим там antigravity.py

Его содержимое:

антигравитация

import webbrowser
import hashlib

webbrowser.open("https://xkcd.com/353/")

def geohash(latitude, longitude, datedow):
    '''Compute geohash() using the Munroe algorithm.

    >>> geohash(37.421542, -122.085589, b'2005-05-26-10458.68')
    37.857713 -122.544543

    '''
    # https://xkcd.com/426/
    h = hashlib.md5(datedow).hexdigest()
    p, q = [('%f' % float.fromhex('0.' + x)) for x in (h[:16], h[16:32])]
    print('%d%s %d%s' % (latitude, p[1:], longitude, q[1:]))

При импорте видим как открывается наш дефолтный браузер и в нем страничка

с комиксом про питон.

https://xkcd.com/353/

Кстати, в antigravity, как видите, есть еще функция geohash, которая как несложно догадаться

генерирует хэш из широты, долготы и даты.

Что у нас еще есть? Правильно, __future__ модуль. Для него выделен аж отдельный c файл в папке исходники/Python. Если кто не знал, когда Вы пишите from __future__ import feature

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

Код на си
//сначала куча нужных инклудов
#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
#define ERR_LATE_FUTURE \
"from __future__ imports must occur at the beginning of the file"
//определяем сообщения об ошибках

static int
future_check_features(PyFutureFeatures *ff, stmt_ty s, PyObject *filename)
{
    int i;
    asdl_seq *names;

    assert(s->kind == ImportFrom_kind);

    names = s->v.ImportFrom.names;
    for (i = 0; i < asdl_seq_LEN(names); i++) {
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
        const char *feature = PyUnicode_AsUTF8(name->name);
        if (!feature)
            return 0; //если не нашли фичу, то выходим
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
            continue; 
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
            continue; //ищим поддержку генераторов, если есть продолжаем
        } 
       //дальше идет список фич и везде проверка выглядит как в случае с генераторами
       //только названия фич другое
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
        } else if (strcmp(feature, FUTURE_GENERATOR_STOP) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_ANNOTATIONS) == 0) {
            ff->ff_features |= CO_FUTURE_ANNOTATIONS;
        } else if (strcmp(feature, "braces") == 0) {
            PyErr_SetString(PyExc_SyntaxError,
                            "not a chance");
           //а если импортируем фигурные скобки,то питон выбросит такую ошибку
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
            return 0;
        } else {
            PyErr_Format(PyExc_SyntaxError,
                         UNDEFINED_FUTURE_FEATURE, feature);
            //какая-то непонятная фича, выбрасываем ошибку
            PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset + 1);
            return 0;
        }
    }
    return 1;
}

       //вырезанный не очень интересный код

        if (s->kind == ImportFrom_kind) {
            identifier modname = s->v.ImportFrom.module;
            if (modname &&
                _PyUnicode_EqualToASCIIString(modname, "__future__")) {
               //задаем название модуля
                if (done) {
                    PyErr_SetString(PyExc_SyntaxError,
                                    ERR_LATE_FUTURE);
                  //а вот здесь выбрасываем ошибку если импортируем не в начале файла
                    PyErr_SyntaxLocationObject(filename, s->lineno, s->col_offset);
                    return 0;
                }
                if (!future_check_features(ff, s, filename))
                    return 0;
                ff->ff_lineno = s->lineno;
            }
            else {
                done = 1;
            }
        }
        else {
            done = 1;
        }
    }
    return 1;
}

Ну вот кажется и все :-)

Но и под конец мем про питон, это ведь позитивно!

P.S.: Надеюсь, никто из кодеров на перле не обиделся, на нем много всего классного написано.



Лучшая Python рассылка




Разместим вашу рекламу

Пиши: mail@pythondigest.ru

Нашли опечатку?

Выделите фрагмент и отправьте нажатием Ctrl+Enter.

Система Orphus