2.6Kпросмотров
18 декабря 2022 г.
Score: 2.8K
By: quantum super position, MVC Введение Сегодня мы научимся добавлять свою функцию в builtins¹ эталонной реализации языка программирования Python - CPython. Перед тем как приступить, давайте определимся какую функцию мы хотим добавить. В builtins присутствует функция abs, её задача - вызывать у объекта dunder-method(магический метод) abs. Обычно abs используют для того, что бы вернуть модуль какого-то числа. Помимо dunder-method'a abs у числовых типов обычно присутсвует neg, который отрицает число. Но в builtins функции neg которая бы вызывала этот dunder нет! Именно реализацией этого мы с вами сегодня и займемся. Замечание: Стоит отметить, что на самом деле number может вызывать neg, но отдельной функции под это нет. Видимо это сделанно из соображений красоты. Реализация Начнём с установки. Склонируем репозиторий интерпретатора: git clone --depth 1 --branch 3.11 https://github.com/python/cpython Затем перейдем в директорию cpython: cd cpython Теперь откроем Objects/abstract.c и реализуем функцию PyNumber_Negate: PyObject PyNumber_Negate(PyObject object) { if (object == NULL) { return null_error(); } PyNumberMethods methods = Py_TYPE(object)->tp_as_number; if (methods && methods->nb_negative) { PyObject res = methods->nb_negative(object); assert(_Py_CheckSlotResult(object, "neg", res != NULL)); return res; } return type_error("bad operand type for neg(): '%.200s'", object);
} Эта функция получается в виде аргументов указатель на PyObject,
далее проверяем, не указывает ли object на NULL
Следущим шагом мы получаем методы object.
"if" здесь нам нужен что бы проверить, есть ли метод nb_negative и neg у объекта.
Если таковых нет, то возвращаем исключение type_error("bad operand type for neg(): '%.200s'", object) Иначе возвращаем ng_negative объекта, можно считать что это neg. Теперь откроем заголовочный файл Include/abstract.h и объявим наш PyNumber_Negate: PyAPI_FUNC(PyObject ) PyNumber_Negate(PyObject o); Регистрация Для начала откроем Python/bltinmodule.c и реализуем функцию builtin_neg: static PyObject builtin_neg(PyObject modle, PyObject *x){ return PyNumber_Negate(x);
} Это и есть реализация нашего будущего neg.
Она вызывает функцию PyNumber_Negate, которая в свою очередь и делает все проверки, и в случае их успеха, возвращает нам neg. Затем открываем файл Python/clinic/bltinmodule.c.h, тут мы обьявим макрос BUILTIN_NEG_METHODDEF. Но перед этим стоит написать небольшую документацию нашего метода, которая будет отображаться при вызове help(neg): PyDoc_STRVAR(builtin_negdoc,
"neg($module, x, /)\n"
"--\n"
"\n"
"Return the negate value of the argument."); Теперь объявим наш макрос: #define BUILTIN_NEG_METHODDEF \ {"neg", (PyCFunction)builtin_neg, METH_O, builtin_negdoc},
В дефайне макроса, как мы видим мы передаём название билтина neg, и функцию реализующую его (PyCFunction)builtin_neg
Теперь вернемся к Python/bltinmodule.c
Здесь нам нужно найти static PyMethodDef builtin_methods[], и добавить в него наш макрос BUILTNI_NEG_METHODDEF
После добавления, static PyMethodDef builtin_methods[] будет выглядеть как-то так: static PyMethodDef builtin_methods[] = { {"build_class", _PyCFunction_CAST(builtin_build_class), METH_FASTCALL | METH_KEYWORDS, build_class_doc}, BUILTIN_IMPORT_METHODDEF BUILTIN_ABS_METHODDEF BUILTIN_ALL_METHODDEF BUILTIN_ANY_METHODDEF BUILTIN_ASCII_METHODDEF BUILTIN_BIN_METHODDEF BUILTIN_NEG_METHODDEF // а вот и наш макрос! // здесь еще куча макросов и остального
}; Мы добавили нашу функцию в builtins питона! Осталось всё это запустить. Сборка Если у вас UNIX like OS, то для того что бы начать сборку вам нужно ввести в терминал следующее:
./configure --with-py-debug
Флаг --with-py-debug означает что мы собираем Python для дебага, и там не будет некоторых оптимизаций, что, конечно, ускорит сборку.
Далее вводим make -j 2 за