Написание расширений Python, несомненно, является одним из способов улучшения Python, но вы также можете разветвить репозиторий и создать свою версию интерпретатора Python.
На практике вам, вероятно, нечасто приходится создавать Python самостоятельно как пользователю. Но полезно поиграть с ним, чтобы ознакомиться с кодовой базой Python и понять, что делает Python C API. Этот учебный опыт, несомненно, поможет вам писать более качественный код расширения и придаст вам больше уверенности при оценке правильности вашего кода.
Собрать Python
git clone [email protected]:python/cpython.git --depth=1 cd cpython mkdir debug # Built artifacts are stored in the debug folder cd debug ../configure --with-pydebug --enable-optimizations --with-lto make -j8 # change 8 to the number of CPUs on your workstation
После создания вы можете найти исполняемый файл с именем python
по текущему пути (в папке debug
).
Обновите реализацию встроенного модуля Python.
Теперь давайте настроим модуль словаря, изменив его строку документации, определенную в этой переменной C.
# You should be in the `debug` folder # Edit Objects/dictobject.c and update `dictionary_doc` vim ../Objects/dictobject.c make -j8 build_all ./python >>> print(dict.__doc__) <- You should be able to see the new string
Поздравляем! Вы только что внесли первое изменение в интерпретатор Python!
Адаптация встроенных модулей Python
Мы также можем удалить определенные модули, обновив файл конфигурации Setup
.
# You should be in the `debug` folder # Comment out the last line (pwd module) by prepending # vi Modules/Setup.bootstrap # Rebuild Python make -j8 build_all # Now let's verify that the pwd module no longer exists ./python >>> import pwd Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'pwd'
Добавление нового встроенного модуля
В кодовой базе CPython уже есть исчерпывающий пример встроенного модуля с именем xxmodule.c (обратите внимание, что этот файл находится в родительской папке, а не в папке debug
). Этот пример также можно использовать в качестве шаблона при написании новых модулей.
Давайте включим xxmodule
, чтобы вы могли видеть, что происходит. Я настоятельно рекомендую вам ознакомиться с его исходным кодом, так как pybind11 является хорошей оболочкой C++ для этих кодов C, и вы узнаете, как был разработан код оболочки позже в этой серии.
# Still in the `debug` folder # Enable xxmodule by adding a new line with content `xx xxmodule.c`. # Make sure to finish this file with an empty space vi Modules/Setup.local # Rebuild Python make -j8 build_all ./python >>> import xx >>> xx.Str('hi') 'hi' >>> xx.bug([1,2,3]) 1
Тест: после прочтения исходного кода вы поняли, в чем ошибка метода bug
?
Ответ: это очень тонкая ошибка, связанная с подсчетом ссылок. Проверьте здесь для отличного объяснения. И ниже приведен пример кода, который вызывает эту ошибку:
>>> class ValueA: ... def __del__(self): ... print("A is removed\n") ... >>> class ValueB: ... def __del__(self): ... print("B is removed\n") ... global input ... del input[0] ... >>> input = [ValueA(), ValueB()] >>> xx.bug(input) B is removed A is removed <refcnt -2459565876494606883 at 0x7f8b47e61c30> <- weird output >>> input [0] >>> input = [ValueA(), ValueB()] >>> input [<__main__.ValueA object at 0x7f8b47b4fbc0>, <__main__.ValueB object at 0x7f8b47b4edb0>] >>> input[0] <__main__.ValueA object at 0x7f8b47b4fbc0> <- expected output
Если вам интересно, в той же папке есть другие примеры, такие как xxlimited.c и xxsubtype.c, для справки.