Cpython что это
Перейти к содержимому

Cpython что это

  • автор:

Почему существует так много Питонов?

Удивительно, но это довольно неоднозначное заявление. Что я имею ввиду под “Питоном”? Может, абстрактный интерфейс Питона? Или CPython, распространенная реализация Питона (не путать с похожим по названию Cython)? Или я имею ввиду что-то совсем иное? Может, я косвенно ссылаюсь на Jython, или IronPython, или PyPy. Или может я отвлекся так сильно, что говорю о RPython или RubyPython (которые очень сильно отличаются).

Не смотря на схожесть в названиях указанных выше технологий, некоторые из них имеют совсем другие задачи (или, как минимум, работают совершенно иными способами)

При работе с Питоном я столкнулся с кучей таких технологий. Инструменты *ython. Но лишь недавно я уделил время, чтобы разобраться, что они собой представляют, как они работают и почему они (каждая по-своему) необходимы.

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

Все начинается с понимания того, чем на самом деле является “Питон”.

Если у вас хорошее понимание машинного кода, виртуальных машин и так далее, можете пропустить этот раздел.

Питон интерпретируемый или компилируемый?

Это распространенный источник непонимания среди новичков Питона.

Первое, что необходимо понять: “Питон” – это интерфейс. Существует спецификация, описывающая, что должен делать Питон, и как он должен себя вести (что справедливо для любого интерфейса). И существует несколько имплементаций (что также справедливо для любого интерфейса).

Второе: “интерпретируемый” и “компилируемый” это свойства имплементации, но не интерфейса.

Так что сам вопрос не совсем корректен.

В случае с самой распространенной реализацией (CPython: написанный на C, часто называемый просто “Python”, и, конечно, именно тот, который вы используете, если понятия не имеете о чем я толкую) ответ: интерпретируемый, с некоторой компиляцией. CPython компилирует* исходный код на Питоне в байткод, а затем интерпретирует этот байткод, запуская его в процессе.

* Замечание: это не совсем “компиляция” в традиционном смысле. Обычно, мы считаем, что “компиляция” это конвертация из высокоуровневого языка в машинный код. Тем не менее – в некотором роде это “компиляция”.

Давайте изучим этот ответ получше, так как он поможет нам понять некоторые концепции, ожидающие нас в этой статье.

Байткод или машинный код

Очень важно понять разницу между байткодом и машинным (или нативным) кодом. Пожалуй, легче всего ее понять на примере:

— Cи компилируется в машинный код, который впоследствии запускается напрямую процессором. Каждая инструкция заставляет процессор производить разные действия.
— Java компилируется в байткод, который впоследствии запускается на Виртуальной машине Java (Java Virtual Machine, JVM), абстрактном компьютере, который запускает программы. Каждая инструкция обрабатывается JVM, который взаимодействует с компьютером.

Сильно упрощая: машинный код намного быстрее, но байткод лучше переносим и защищен.

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

Возвращаясь к CPython, цепочка операций выглядит следующим образом:

1. CPython компилирует ваш исходный код на Питоне в байткод.
2. Этот байткод запускается на виртуальной машине CPython.

Новички зачастую допускают, что Питон компилируемый из-за наличия .pyc-файлов. Это отчасти верно: .pyc-файлы – это скомпилированный байткод, который впоследствии интерпретируется. Так что если вы запускали ваш код на Питоне, и у вас есть .pyc-файл, то во второй раз он будет работать быстрее, потому что ему не нужно будет заново компилироваться в байткод.

Альтернативные виртуальные машины: Jython, IronPython и другие

Как я говорил выше, у Питона существует несколько реализаций. Опять же, как говори-лось выше, самой популярной является CPython. Эта версия Питона написана на C и считается имплементацией “по умолчанию”.

Но как насчет альтернатив? Одна из наиболее видных это Jython, реализация Питона на Java, которая использует JVM. В то время как CPython генерирует байткод для запуска на CPython VM, Jython генерирует байткод Java для запуска на JVM (это то же самое, что генерируется при компиляции программы на Java).

“Зачем может понадобиться использовать альтернативную реализацию?”, спросите вы. Ну, для начала, разные реализации хорошо ладят с разными наборами технологий.

CPython упрощает написание C-расширений для кода на Питоне потому что в конце он запускается интерпретатором Cи. Jython в свою очередь упрощает работу с другими программами на Java: вы можете импортировать любые Java-классы без дополнительных усилий, призывая и используя ваши Java-классы из программ на Jython. (Замечание: если вы еще не думали об этом всерьез, это довольно безумно. Мы дожили до того времени, когда можно смешивать разные языки и компилировать их в одну сущность. Как заметил Rostin, программы, смешивающие код на Фортране с Cи появились довольно давно, так что это не совсем новинка. Но это все же круто.)

В качестве примера, вот корректный код на Jython:

[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_51
>>> from java.util import HashSet
>>> s = HashSet(5)
>>> s.add(«Foo»)
>>> s.add(«Bar»)
>>> s
[Foo, Bar]

IronPython это другая популярная реализация Питона, написанная полностью на C# и предназначенная для .NET. В частности, она запускается на виртуальной машине .NET, если ее можно так назвать, на Common Language Runtime (CLR), от Майкрософт, сравнимым с JVM.

Можно сказать, что Jython: Java :: IronPython: C#. Они работают на соответствующих виртуальных машинах, есть возможность импортировать классы C# в код IronPython и классы Java в код Jython, и так далее.

Вполне реально выжить, не прикасаясь к ни к чему, кроме CPython. Но, переходя на другие имплементации, вы получаете преимущество, в основном из-за используемого стека технологий. Используете много языков, основанных на JVM? Jython может вам подойти. Все на .NET? Возможно, стоит попробовать IronPython (и, возможно, вы уже сделали).

Кстати, хоть это и не станет причиной для перехода на другую имплементацию, стоит упомянуть, что имплементации эти на самом деле отличаются поведением. Это касается не только способов интерпретации кода на Питоне. Однако эти отличия, как правило, не-значительны, они исчезают и появляются со временем из-за активной разработки. К примеру, IronPython использует строки Unicode по умолчанию; однако CPython использует ASCII в версиях 2.x (выдавая ошибку UnicodeEncodeError для не-ASCII символов), и при этом поддерживает символы Unicode по умолчанию в версиях 3.x.

Компиляция на лету (Just-in-Time Compilation): PyPy и будущее

Итак, у нас есть имплементация Питона, написанная на Си, еще одна – на Java, и третья на C#. Следующий логичный шаг: имплементация Питона, написанная на… Питоне. (Подготовленный читатель заметит, что это утверждение немного обманчиво).

Вот почему это может сбивать с толку. Для начала, давайте обсудим компиляцию на лету (just-in-time или JIT).

JIT. Почему и как

Напомню, что нативный машинный код намного быстрее байткода. Ну, а что, если бы можно было компилировать часть байткода и запускать его как нативный код? Пришлось бы “заплатить” некоторую цену (иными словами: время) за компиляцию байткода, но если результат будет работать быстрее, то это здорово! Этим и мотивируется JIT-компиляция, гибридная техника, которая совмещает в себе преимущества интерпретато-ров и компиляторов. В двух словах – JIT старается использовать компиляцию, чтобы ускорить систему интерпретации.

Например, вот распространенный подход JIT:

  1. Определить байткод, который запускается часто.
  2. Скомпилировать его в нативный машинный код.
  3. Закэшировать результат.
  4. Всегда когда необходимо запустить тот же самый байткод, использовать уже скомпилированный машинный код и пожинать плоды (в частности, прирост скорости).

В этом вся суть PyPy: использовать JIT в Питоне (в дополнении можно найти предыдущие попытки). Конечно, есть и другие цели: PyPy нацелен на кроссплатформенность, работу с небольшим количеством памяти и поддержку stackless (отказа от стека вызовов языка Си в пользу собственного стека). Но JIT это главное преимущество. В среднем на основе временных тестов, фактор ускорения составляет 6.27. Более подробные данные можно получить из схемы от PyPy Speed Center:

В PyPy сложно разобраться

У PyPy есть огромный потенциал, и в данный момент он хорошо совместим с CPython (так что на нем можно запускать Flask, Django, и т.д.).

Но с PyPy есть много путаницы. (оцените, к примеру, это бессмысленное предложение создать PyPyPy…). По моему мнению основная причина в том, что PyPy одновременно является:

1. Интерпретатором Питона, написанным на RPython (не Python (я обманул вас до этого)). RPython это подмножество Python со статичной типизацией. В Python, вести тщательные беседы о типах “в целом невозможно” почему это так сложно? рассмотрите следующее:

x = random.choice([1, «foo»])

это корректный код на Python (спасибо Ademan‘у). Какой тип у x? Как мы можем обсуждать типы переменных, когда типы даже не форсируются?). В RPython мы жертвуем некоторой гибкостью, но взамен получаем возможность гораздо проще управлять памятью и много чего еще, что помогает при оптимизации.

2. Компилятором, который компилирует код на RPython в разные форматы и поддерживает JIT. Платформой по-умолчанию является Си, то есть компилятор RPython-в-Си, но в качестве целевой платформы также можно выбрать JVM и другие.

Для простоты описания, я буду называть их PyPy (1) и PyPy (2).

Зачем могут понадобиться эти две вещи, и почему – в одном наборе? Думайте об этом так: PyPy (1) это интерпретатор, написанный на RPython. То есть он берет пользовательский код на Питоне и компилирует его в байткод. Но чтобы сам интерпретатор (написанный на RPython) мог работать, он должен быть интерпретирован другой реализацией Пи-тона, верно?

Итак, можно просто использовать CPython чтобы запускать интерпретатор. Но это будет не слишком быстро.

Вместо этого мы используем PyPy (2) (называемый RPython Toolchain) чтобы компилировать интерпретатор PyPy в код для другой платформы (например, C, JVM, или CLI) для запуска на конечной машине, с добавлением JIT. Это волшебно: PyPy динамически добавляет JIT к интерпретатору, генерируя собственный компилятор! (Опять же, это безумие: мы компилируем интерпретатор, добавляя другой отдельный, самостоятельный компилятор).

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

Повторим: настоящая красота PyPy в том, что мы можем написать себе кучу разных интерпретаторов Питона на RPython не волнуясь о JIT (не считая пары деталей). После этого PyPy реализует для нас JIT, используя RPython Toolchain/PyPy (2).

На самом деле, если копнуть глубже в абстракцию, теоретически можно написать интерпретатор любого языка, направить его в PyPy и получить JIT для этого языка. Это возможно потому, что PyPy концентрируется на оптимизации самого интерпретатора, а не деталей языка, который тот интерпретирует.

В качестве отступления я бы хотел заметить, что сам JIT совершенно восхитителен. Он использует технику под названием “отслеживание” (tracing), которая работает следующим образом:

  1. Запустить интерпретатор и интерпретировать все (не добавляя JIT).
  2. Провести легкое профилирование интерпретированного кода.
  3. Определить операции, которые уже выполнялись ранее.
  4. Скомпилировать эти части кода в машинный код.

Узнать больше можно из этой легкодоступной и очень интересной публикации.

Подытожим: мы используем PyPy-компилятор RPython-в-Си (или другую целевую плат-форму), чтобы скомпилировать реализованный на RPython интерпретататор PyPу.

Заключение

Почему все это так восхитительно? Почему стоит гнаться за этой безумной идеей? По-моему, Алекс Гейнор объяснил это очень хорошо в своем блоге: “[За PyPy будущее] потому что [он] более быстрый, более гибкий и является лучшей платформой для развития Питона”.

  • Он быстрый – потому что компилирует исходный код в нативный код (используя JIT).
  • Он гибкий – потому что добавляет JIT в интерпретатор без особых усилий.
  • Он гибкий (опять) – потому что вы можете писать интерпретаторы в RPython, что впоследствии упрощает расширение по сравнению с тем же Си (на самом деле упрощает настолько, что даже есть инструкция по написанию собственных интерпретаторов).
Дополнение: другие названия, которые вы, возможно, слышали

Python 3000 (Py3k): альтернативное название Python 3.0, основной релиз Питона с обратной совместимостью, который появился в 2008. году. Команда Py3k предсказала, что новой версии понадобится примерно пять лет чтобы полностью прижиться. И в то время, как большинство (внимание: надуманное утверждение) разработчиков на Питоне продолжают использовать Python 2.x, люди все больше задумываются о Py3k.

  • Задача: позволить писать расширения Си для программ на Питоне.
  • Также позволяет добавлять статическую типизацию в существующий код на Питоне, что после повторной компиляции может помочь достичь похожей на Си производительности.
  • Напоминает PyPy, но это не то же самое. В случае с Cython вы форсируете типизацию в пользовательском коде перед подачей компилятору. В PyPy вы пишете старый добрый Python, а компилятор отвечает за любую оптимизацию.

Numba: “специализированный just-in-time компилятор”, который добавляет JIT в снабженный примечаниями код на Питоне. Проще говоря, вы даете ему подсказки, а он ускоряет некоторые части вашего кода. Numba является частью дистрибутива Anaconda набора пакетов для анализа и управления данными.

IPython: сильно отличается от всего, что мы обсудили. Вычислительная среда для Питона. Интерактивная, с поддержкой GUI-пакетов, браузеров и так далее.

Psyco: модуль расширения Питона, одна из первых попыток Питона в области JIT. Давно помечен как “неподдерживаемый и мертвый”. Главный разработчик Psyco Армин Риго сейчас работает над PyPy.

Привязки к языкам
  • RubyPython: мост между виртуальными машинами Ruby и Python. Позволяет встраивать код на Питоне в код на Ruby. Вы обозначаете, где начинается и заканчивается Питон, а RubyPython обеспечивает передачу данных между виртуальными машинами.
  • PyObjc: языковое соединение между Python и Objective-C, которые ведет себя как мост между ними. На практике это означает, что вы можете использовать библиотеки Objective-C (включая все, что нужно для создания приложения под OS X) в коде на Питоне, и модули Питона в коде на Objective-C. Это удобно, потому что CPython написан на Си, который является подмножеством Objective-C.
  • PyQt: в то время как PyObjc позволяет связать Питон с компонентами OS X GUI, PyQt делает то же для фреймворка Qt. Это дает возможность создавать полноценные графические интерфейсы, обращаться к SQL базам данных и так далее. Еще один инструмент, нацеленный на перенос простоты Питона в другие фреймворки.
JavaScript фреймворки
  • pyjs (Pyjamas): фреймворк для создания веб и десктопных приложений на Питоне. Включает в себя компилятор Python-в-JavaScript, набор виджетов и некоторые другие инструменты.
  • Brython: виртуальная машина Python, написанная на Javascript. Позволяет запустить код на Py3k в веб-браузере.

CPython

CPython — наиболее распространённая, эталонная реализация языка программирования Python. CPython является интерпретатором байт-кода, написан на C. Разработка CPython ведётся группой разработчиков под руководством создателя Python Гвидо ван Россума. CPython является программным обеспечением с открытым исходным кодом.

Кроме CPython, существуют другие реализации Python: Jython, IronPython, PyPy, Stackless Python.

Поддерживаемые платформы

Более не поддерживаемые платформы

В PEP 11 перечислены платформы, которые более не поддерживаются Python Software Foundation. Тем не менее эти платформы могут иметь поддержку от других дистрибьюторов. Список неподдерживаемых платформ:

  • DOS (не поддерживается начиная с 2.0)
  • IRIX 4 (не поддерживается начиная с 2.3)
  • Mac OS 9 (не поддерживается начиная с 2.4)
  • MINIX (не поддерживается начиная с 2.3)

Внешние порты

Существуют платформы, поддержка которых отсутствует в официальном дистрибутиве CPython, но имеется у внешних дистрибьюторов. Эти дистрибутивы часто включают дополнительные возможности для поддерживаемых платформ. Список этих платформ:

  • Amiga: AmigaPython
  • AS/400: iSeriesPython
  • DOS с использованием DJGPP: PythonD
  • PlayStation Portable: Stackless Python for PSP
  • Symbian OS: Python for S60
  • Windows CE/Pocket PC: Python Windows CE port

Основные реализации Python: характеристика и преимущества

В этой статье мы расскажем вам о CPython, Jython, IronPython, PyPy и Cython. Поговорим об их основных отличиях и преимуществах.

Листья деревьев разных видов

Область компьютерных наук является, пожалуй, самой популярной в наши дни. И она всё ещё продолжает расти и развиваться. То, что представляют из себя компьютерные науки сейчас, совсем не похоже на то, чем они были в самом начале. Благодаря Computer Science, теперь есть возможность создавать вещи, которые волшебным образом меняют жизни миллионов людей! Такой разительный прогресс позволил создать искусственный интеллект, глубокое обучение и многие другие концепции, которые раньше считались невозможными.

Языки программирования в целом являются одним из наиболее стремительно развивающихся элементов компьютерных наук. Но развиваются они неравномерно. Возьмем к примеру Python. Это высокоуровневый язык программирования, который очень вырос со времени своего выхода в свет и сейчас используется в самых разных сферах. В результате он выделяется даже на фоне других успешно развивающихся языков.

Стоит отметить, что сам по себе Python довольно многообразен и используется в различных реализациях. Это и будет темой нашей статьи: мы рассмотрим разные способы реализации этого языка, существующие на данный момент.

Основные реализации Python

Мы уже несколько раз использовали термин «реализация». Но что под этим подразумевается? Говоря о реализации, мы имеем в виду то, как был написан интерпретатор – какие языки были использованы и какова главная задача конкретно этого интерпретатора.

А теперь давайте разберем некоторые реализации Python.

1. CPython

python

CPython – это, по сути, дефолтный и наиболее распространенный интерпретатор (реализация) языка Python, написанный на C. Это изначальная версия языка, которую пользователи скачивают с официального сайта – Python.org.

Лучше всего CPython можно описать как некую смесь интерпретатора и компилятора, так как написанный вами код преобразуется в байт-код. Под байт-кодом мы понимаем программный код, который компилируется и преобразуется в низкоуровневый язык, который, в свою очередь, может быть использован как набор инструкций для интерпретатора. Именно этот байт-код и выполняется на виртуальной машине CPython.

Поскольку это «родная» реализация Python, CPython наиболее совместим с пакетами и модулями языка. Эта реализация будет наилучшим выбором, если вам нужно написать код, полностью соответствующий стандартам Python.

2) Jython

Лого jython - реализации Python

Jython – это ещё одна реализация Python. Она была написана на Java и работает на Java-платформах. Как и в CPython, исходный код конвертируется в байт-код – набор инструкций для интерпретатора. Jython работает на виртуальной машине, которая использует то же окружение, что и Java. Данная реализация обеспечивает удобную работу с Java-программами. Вы легко сможете вызывать и использовать свои функции и классы Java непосредственно из Jython. Это дает пользователям Python доступ к огромнейшей экосистеме библиотек и фреймворков, имеющихся в Java. И наоборот.

3) IronPython

ironpython

Если Jython был разработан для пользователей Java, то IronPython — популярная реализация, написанная на C#. Её разработали для работы на платформе .NET. Она создает мост во вселенную .NET, дающий пользователям Python доступ к функциям и классам C#, библиотекам и фреймворкам .NET прямо из IronPython. Данная реализация отлично подходит для многопоточных программ. Вы можете её найти на официальном сайте — ironpython.net.

4) PyPy

Эта реализация написана на самом Python и является альтернативой CPython. PyPy был написан с учетом всех особенностей языка Python, поэтому он наиболее совместим с CPython. Это позволяет запускать веб-фреймворки, такие как Django и Flask. PyPy использует концепцию JIT-компиляции (Just-in-time), которая позволяет компилировать исходный код прямо во время выполнения программы. Это делает PyPy в несколько раз быстрее CPython. Многие пользователи последнего жаловались именно на низкую скорость выполнения. Таким образом, PyPy полностью улучшает эту часть CPython.

5) Cython

Лого Cython - реализации Python

В отличие от других реализаций Python, упомянутых выше, Cython не является интерпретатором Python. Это, скорее, надмножество языка Python, которое дает возможность пользователям компилировать программы на языке C.

Вообще, объединенная мощь Python и C — самое потрясающее в Cython. Благодаря ей Cython можно использовать для написания расширений C, а также для преобразования Python-кода в C. Таким образом, Cython сохраняет удобство и комфорт, за которые все так любят Python, устраняя многие ограничения последнего.

Заключение

Python за годы своего активного развития очень расширился. Различные реализации этого языка удовлетворяют нужды разных пользователей. Если вы планируете писать код на Python на профессиональном уровне, высока вероятность, что со временем вы столкнетесь с несколькими из упомянутых реализаций. И когда это произойдет, нужно уметь распознать, с чем именно вы столкнулись, и почему для данного кода выбрана именно такая реализация Python.

О компиляции и (полу)компиляции в CPython

Python_Deep_10.12_site-5020-79682c.png

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

Дубль два

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

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

Исходный код можно скомпилировать в байт-код с разными флагами оптимизации: -О, -ОО. В результате у вас появятся *.pyo файлики с байт-кодом. При этом в первом случае у вас будут «выключены» assert’ы, а во втором — ещё «вырежутся» docstring’и. Оптимизации не особо крутые, чего уж тут говорить, если только в asserta’ах не было какой-то сложной логики.

И что это значит с практической точки зрения?

Как это знание может пригодиться? Например, если код разворачивается на CentOS с помощью rpm-пакетов, то во время сборки пакета неявно запускается brp-python-bytecompile скрипт, который компилирует Python файлы в .pyc и .pyo. Поэтому не стоит потом удивляться, что assert’ы в коде не срабатывают.

Хотите задать вопрос? Пишите комментарий!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *