Python против C ++: выбор правильного инструмента для работы

Python против C ++: выбор правильного инструмента для работы

Вы разработчик C, сравнивающий Python и C? Вы смотрите на Python и задаетесь вопросом, о чем весь этот шум? Вам интересно, как Python сравнивается с концепциями, которые вы уже знаете? Или, может быть, у вас есть ставка на то, кто победит, если вы заперли C ++ и Python в клетке и позволили им сражаться? Тогда эта статья для вас!

In this article, you’ll learn about:

  • Различия и сходства, когда вы сравниваете Python с C ++

  • Времена, когда Python может быть лучшим выбором для проблемы, и наоборот

  • Ресурсы, к которым можно обратиться, поскольку у вас есть вопросы при изучении Python

Эта статья предназначена для разработчиков на языке C, изучающих Python. Он предполагает базовое знание обоих языков и будет использовать концепции от Python 3.6 и выше, а также C11 или новее.

Давайте погрузимся в изучение Python против C ++!

Free Bonus:Click here to get access to a chapter from Python Tricks: The Book, который демонстрирует вам лучшие практики Python на простых примерах, которые вы можете мгновенно применить для написания более красивого кода Pythonic.

Сравнение языков: Python против C ++

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

Когда вы сравниваете Python с C ++, помните, что они оба являются инструментами, и они оба используют для разных задач. Подумайте о сравнении молотка и отвертки. Вы,could, забиваете гвозди отверткой, а вы,could, забиваете шурупы молотком, но ни то, ни другое не поможет.

Использование правильного инструмента для работы важно. В этой статье вы узнаете о функциях Python и C, которые делают каждую из них правильным выбором для определенных типов проблем. Так что не рассматривайте «vs» в Python vs C как значение «против». Скорее воспринимайте это как сравнение.

Компиляция против виртуальной машины

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

Compiling a C++ program for windows.

Этот процесс выводит фактические машинные инструкции для конкретного процессора и операционной системы, для которых он создан. На этом рисунке это программа для Windows. Это означает, что вам придется перекомпилировать свою программу отдельно для Windows, Mac и Linux:

Compiling a C++ program on three operating systems.

Скорее всего, вам придется изменить свой код C ++ для работы на этих разных системах.

Python, с другой стороны, использует другой процесс. Теперь помните, что вы будете смотреть наCPython, который является стандартной реализацией языка. Если вы не делаете что-то особенное, это Python, который вы используете.

Python запускается каждый раз, когда вы запускаете вашу программу. Он компилирует ваш исходный код так же, как компилятор C ++. Разница в том, что Python компилируется вbytecode вместо машинного кода. Байт-код - это собственный код инструкции дляPython virtual machine. Чтобы ускорить последующие запуски вашей программы, Python сохраняет байт-код в файлах.pyc:

Python compiles a py file into a pyc file.

Если вы используете Python 2, вы найдете эти файлы рядом с файлами.py. Для Python 3 вы найдете их в каталоге__pycache__.

Сгенерированный байт-код не работает на вашем процессоре. Вместо этого он запускается виртуальной машиной Python. Это похоже на виртуальную машину Java или .NET Common Runtime Environment. Первоначальный запуск вашего кода приведет к шагу компиляции. Затем байт-код будет интерпретирован для запуска на вашем конкретном оборудовании:

Python compiles a py file into a pyc file and then executes it.

Пока программа не была изменена, каждый последующий запуск будет пропускать этап компиляции и использовать ранее скомпилированный байт-код для интерпретации:

Python executes a pyc file.

Интерпретация кода будет медленнее, чем запуск собственного кода непосредственно на оборудовании. Так почему же Python работает именно так? Что ж, интерпретация кода в виртуальной машине означает, что только виртуальная машина должна быть скомпилирована для конкретной операционной системы на конкретном процессоре. Весь код Python, который он запускает, будет работать на любой машине с Python.

Note: CPython написан на C, поэтому он может работать в большинстве систем, в которых есть компилятор C.

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

Например, с помощьюpathlib можно управлять разделителями путей независимо от того, работаете ли вы в Windows, Mac или Linux. Разработчики этих библиотек потратили много времени на то, чтобы сделать его переносимым, так что вам не нужно беспокоиться об этом в вашей программе на Python!

Прежде чем двигаться дальше, давайте начнем отслеживать сравнительную таблицу Python и C ++. Когда вы осветите новые сравнения, они будут добавлены курсивом:

Особенность питон C++

Более быстрое выполнение

x

Кросс-платформенное исполнение

x

Теперь, когда вы увидели различия во время выполнения, сравнивая Python с C ++, давайте углубимся в особенности синтаксиса языков.

Синтаксические различия

Python и C ++ имеют много синтаксических сходств, но есть несколько областей, которые стоит обсудить:

  • Пробелы

  • Логические выражения

  • Переменные и указатели

  • постижения

Давайте начнем с наиболее спорного один первый: пробел.

Пробелы

Первое, что замечает большинство разработчиков при сравнении Python и C, - это «проблема с пробелами». Python использует начальные пробелы для обозначения области видимости. Это означает, что тело блока `+ if +` или другой подобной структуры обозначается уровнем отступа. C использует фигурные скобки ({}) для обозначения той же идеи.

В то время как лексер Python принимает любые пробелы, если вы согласованы,PEP8 (official style guide для Python) указывает 4 пробела для каждого уровня отступа. Большинство редакторов могут быть настроены для этого автоматически.

Уже было написано огромное количествоwriting,shouting иranting о правилах использования пробелов в Python, поэтому давайте перейдем к другим вопросам.

Вместо того, чтобы полагаться на лексический маркер, например;, для завершения каждого оператора, Python использует конец строки. Если вам нужно растянуть оператор на одну строку, вы можете использовать обратную косую черту (\), чтобы указать это. (Обратите внимание, что если вы находитесь внутри набора скобок, то символ продолжения не нужен.)

Есть люди, которые недовольны по обе стороны проблемы пробелов. Некоторым разработчикам Python нравится, что вам не нужно вводить скобки и точки с запятой. Некоторые разработчики C ++ ненавидят зависимость от форматирования. Лучше всего научиться чувствовать себя комфортно с обоими.

Теперь, когда вы рассмотрели проблему пробелов, давайте перейдем к проблеме, которая менее спорна: булевы выражения.

Логические выражения

То, как вы будете использоватьBoolean expressions, немного изменится в Python и C. В C вы можете использовать числовые значения для обозначенияtrue илиfalse в дополнение к встроенным значениям. Все, что оценивается как0, считаетсяfalse, а любое другое числовое значение -true.

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

  • Константы определены как ложные:

    • None

    • False

  • Нули любого числового типа:

    • 0

    • 0.0

    • 0j

    • Decimal(0)

    • Fraction(0, 1)

  • Пустые последовательности и коллекции:

    • ''

    • ()

    • []

    • {}

    • set()

    • range(0)

Все остальные элементы -True. Это означает, что пустой список[] равенFalse, в то время как список, содержащий только ноль[0], остаетсяTrue.

Большинство объектов будут оценивать какTrue, если только объект не имеет__bool__(), который возвращаетFalse, или__len__(), который возвращает 0. Это позволяет вам расширять ваши собственные классы, чтобы они действовали как логические выражения.

Python имеет несколько небольших отличий от C в логических операторах. Во-первых, операторы `+ if +` и `+ while +` не требуют окружающих скобок, как в C. Однако, круглые скобки могут помочь в удобочитаемости, так что примите правильные решения.

Большинство булевых операторов C ++ имеют похожие операторы в Python:

Оператор C ++ Оператор Python

&&

and

`+

+`

or

!

not

&

&

`+

+`

`+

+`

Большинство операторов похожи на C ++, но если вы хотите освежить свои знания, вы можете прочитатьOperators and Expressions in Python.

Переменные и указатели

Когда вы впервые начинаете использовать Python после написания на C, вы можете не задумываться о переменных. Похоже, что в целом они работают так же, как в C. Тем не менее, они не одинаковы. В то время как в C ++ вы используете переменные для ссылки на значения, в Python вы используете имена.

Note: В этом разделе, где вы изучаете переменные и имена в Python и C, вы будете использовать * переменные * для C иnames для Python. В другом месте они оба будут называтьсяvariables.

Во-первых, давайте вернемся немного назад и посмотрим наobject model Python шире.

В Pythoneverything - это объект. Числа хранятся в объектах. Модули хранятся в объектах. И объект классаand, и сам класс являются объектами. Функции также являются объектами:

>>>

>>> a_list_object = list()
>>> a_list_object
[]
>>> a_class_object = list
>>> a_class_object

>>> def sayHi(name):
...      print(f'Hello, {name}')
...
>>> a_function_object = sayHi
>>> a_function_object

Вызовlist() создает новый объект списка, который вы назначаетеa_list_object. Использование имени классаlist само по себе помещает метку на объект класса. Вы также можете разместить новый ярлык для функции. Это мощный инструмент, и, как и все мощные инструменты, он может быть опасным. (Я смотрю на вас, мистер Бензопила.)

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

Если вы наберетеpython в командной строке, то появится REPL, где вы сможете начать вводить код и пробовать все сами!

Возвращаясь к обсуждению Python и C, обратите внимание, что это поведение отличается от того, что вы увидите в C. В отличие от Python, в C ++ есть переменные, которые назначаются ячейке памяти, и вы должны указать, сколько памяти будет использовать эта переменная:

int an_int;
float a_big_array_of_floats[REALLY_BIG_NUMBER];

В Python все объекты создаются в памяти, и вы применяете к ним метки. Сами метки не имеют типов, и их можно наносить на объекты любого типа:

>>>

>>> my_flexible_name = 1
>>> my_flexible_name
1
>>> my_flexible_name = 'This is a string'
>>> my_flexible_name
'This is a string'
>>> my_flexible_name = [3, 'more info', 3.26]
>>> my_flexible_name
[3, 'more info', 3.26]
>>> my_flexible_name = print
>>> my_flexible_name

Вы можете назначитьmy_flexible_name любому типу объекта, и Python просто будет работать с ним.

Когда вы сравниваете Python с C ++, разница между переменными и именами может немного сбивать с толку, но она имеет некоторые превосходные преимущества. Во-первых, в Python у вас нетpointers, и вам никогда не нужно думать о проблемах кучи и стека. В этой статье вы немного углубитесь в управление памятью.

постижения

У Python есть языковая функция под названиемlist comprehensions. Хотя в C ++ можно эмулировать списочные выражения, это довольно сложно. В Python они являются основным инструментом, который преподается начинающим программистам.

Один из способов осмыслить списки состоит в том, что они похожи на сверхзаряженный инициализатор для списков, диктов или наборов. Имея один повторяемый объект, вы можете создать список, а затем отфильтровать или изменить оригинал:

>>>

>>> [x**2 for x in range(5)]
[0, 1, 4, 9, 16]

Этот сценарий начинается с итерируемогоrange(5) и создает список, содержащий квадрат для каждого элемента в итерируемом объекте.

Можно добавить условия к значениям в первой итерации:

>>>

>>> odd_squares = [x**2 for x in range(5) if x % 2]
>>> odd_squares
[1, 9]

if x % 2 в конце этого понимания ограничивает используемые числа отrange(5) только до нечетных.

В этот момент у вас могут возникнуть две мысли:

  1. Это мощный синтаксический прием, который упростит некоторые части моего кода.

  2. Вы можете сделать то же самое в C ++.

Хотя верно, что вы можете создатьvector квадратов нечетных чисел в C ++, это обычно означает немного больше кода:

std::vector odd_squares;
for (int ii = 0; ii < 10; ++ii) {
    if (ii % 2) {
        odd_squares.push_back(ii);
    }
}

Для разработчиков, пришедших из языков C-стиля, составление списков - один из первых заметных способовwrite more Pythonic code. Многие разработчики начинают писать Python со структурой C ++:

odd_squares = []
for ii in range(5):
    if (ii % 2):
        odd_squares.append(ii)

Это совершенно правильный Python. Однако он, скорее всего, будет работать медленнее, и он не так ясен и лаконичен, как понимание списка. Изучение использования списочных представлений не только ускорит ваш код, но также сделает ваш код более Pythonic и легче для чтения!

Note: Когда вы читаете о Python, вы часто видите словоPythonic, используемое для описания чего-либо. Это просто термин, который сообщество использует для описания кода, который является чистым, элегантным и выглядит так, как будто он написан джедаем Python.

std::algorithms в Python

C ++ имеет богатый набор алгоритмов, встроенных в стандартную библиотеку. Python имеет аналогичный набор встроенных функций, которые охватывают ту же почву.

Первым и наиболее мощным из них являетсяin operator, который обеспечивает вполне читаемый тест, чтобы увидеть, включен ли элемент вlist,set илиdictionary:

>>>

>>> x = [1, 3, 6, 193]
>>> 6 in x
True
>>> 7 in x
False
>>> y = { 'Jim' : 'gray', 'Zoe' : 'blond', 'David' : 'brown' }
>>> 'Jim' in y
True
>>> 'Fred' in y
False
>>> 'gray' in y
False

Обратите внимание, что операторin при использовании в словарях проверяет только ключи, а не значения. Об этом свидетельствует итоговый тест'gray' in y.

in можно комбинировать сnot для получения удобочитаемого синтаксиса:

if name not in y:
    print(f"{name} not found")

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

>>>

>>> my_big_list = [10, 23, 875]
>>> my_small_list = [1, 2, 8]
>>> any([x < 3 for x in my_big_list])
False
>>> any([x < 3 for x in my_small_list])
True

Наконец, у вас естьall, который похож наany. Это возвращаетTrueonly, если, как вы уже догадались,all элементов в итерации равныTrue. Опять же, объединение этого со списками позволяет получить мощную языковую функцию:

>>>

>>> list_a = [1, 2, 9]
>>> list_b = [1, 3, 9]
>>> all([x % 2 for x in list_a])
False
>>> all([x % 2 for x in list_b])
True

any иall могут покрывать большую часть той же области, в которой разработчики C ++ смотрят наstd::find илиstd::find_if.

Note: В приведенных выше примерахany иall вы можете удалить скобки ([]) без потери функциональности. (например:all(x % 2 for x in list_a)) При этом используетсяgenerator expressions, что, хотя и весьма удобно, выходит за рамки данной статьи.

Прежде чем перейти к типизации переменных, давайте обновим вашу сравнительную таблицу Python и C ++:

Особенность питон C++

Более быстрое выполнение

x

Кросс-платформенное исполнение

x

Переменные одного типа

x

Переменные нескольких типов

x

постижения

x

Богатый набор встроенных алгоритмов

x

x

Хорошо, теперь вы готовы взглянуть на типизацию переменных и параметров. Пошли!

Статическая и динамическая типизация

Еще одна важная тема, когда вы сравниваете Python и C, - это использование типов данных. C - это статически типизированный язык, а Python - динамически типизированный. Давайте рассмотрим, что это значит.

Статическая печать

C ++ имеет статическую типизацию, что означает, что каждая переменная, которую вы используете в своем коде, должна иметь определенный тип данных, напримерint,char,float и т. Д. Переменной можно присвоить только значения правильного типа, если только вы не перепрыгнете через некоторые обручи.

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

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

Duck Typing

Динамическая типизация часто обозначается какduck typing.. Это странное название, и вы узнаете об этом больше всего через минуту! Но сначала давайте начнем с примера. Эта функция берет объект файла и читает первые десять строк:

def read_ten(file_like_object):
    for line_number in range(10):
        x = file_like_object.readline()
        print(f"{line_number} = {x.strip()}")

Чтобы использовать эту функцию, вы создадите файловый объект и передадите его:

with open("types.py") as f:
    read_ten(f)

Это показывает, как работает основной дизайн функции. Хотя эта функция была описана как «чтение первых десяти строк из файлового объекта», в Python нет ничего, что требовало бы, чтобыfile_like_objectbe был файлом. Пока переданный объект поддерживает.readline(), объект может быть любого типа:

class Duck():
    def readline(self):
        return "quack"

my_duck = Duck()
read_ten(my_duck)

Вызовread_ten() с объектомDuck производит:

0 = quack
1 = quack
2 = quack
3 = quack
4 = quack
5 = quack
6 = quack
7 = quack
8 = quack
9 = quack

В этом сутьduck typing. Поговорка гласит: «Если он похож на утку, плавает, как утка, и крякает, как утка, то, вероятно, этоisутка».

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

Однако здесь есть проблема. Что произойдет, если вы передадите объект, которыйdoesn’t соответствует требуемому интерфейсу? Например, что, если вы передадите число вread_ten(), например:read_ten(3)?

Это приводит к исключению. Если вы не поймаете исключение, ваша программа взорвется сtraceback:

Traceback (most recent call last):
  File "", line 1, in 
  File "duck_test.py", line 4, in read_ten
    x = file_like_object.readline()
AttributeError: 'int' object has no attribute 'readline'

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

Note: Python и C считаются языками https://stackoverflow.com/a/11328980 [строго типизированные]. Хотя C имеет более сильную систему типов, детали этого обычно не имеют значения для тех, кто изучает Python.

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

Шаблоны

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

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

Возможность использовать утку вместо шаблонов делает некоторые вещи намного проще. Но это также может вызвать проблемы, которые трудно обнаружить. Как и во всех сложных решениях, при сравнении Python с C ++ возникают компромиссы.

Проверка типа

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

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

Еще раз, давайте взглянем на вашу сравнительную таблицу Python против C ++:

Особенность питон C++

Более быстрое выполнение

x

Кросс-платформенное исполнение

x

Переменные одного типа

x

Переменные нескольких типов

x

постижения

x

Богатый набор встроенных алгоритмов

x

x

Статическая печать

x

Динамический набор текста

x

Теперь вы готовы перейти к различиям в объектно-ориентированном программировании.

Объектно-ориентированное программирование

Как и C, Python поддерживает https://realpython.com/courses/intro-object-oriated-programming-oop-python/[объектно-ориентированную модель программирования]. Многие из концепций, которые вы изучили на C, переносятся и в Python. Вам все равно нужно будет принять решение оinheritance, composition и множественном наследовании.

сходства

Inheritance между классами работает аналогично в Python и C. Новый класс может наследовать методы и атрибуты от одного или нескольких базовых классов, как вы видели в C. Однако некоторые детали немного отличаются.

Базовые классы в Python не имеют своего конструктора, вызываемого автоматически, как в C ++. Это может сбивать с толку, когда вы переключаете языки.

Multiple inheritance также работает в Python, и у него столько же причуд и странных правил, сколько и в C ++.

Точно так же вы можете также использовать композицию для создания классов, где у вас есть объекты одного типа, содержащие другие типы. Учитывая, что в Python все является объектом, это означает, что классы могут содержать что-либо еще в языке.

Различия

Однако есть некоторые различия, когда вы сравниваете Python с C ++. Первые два связаны.

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

Тот факт, что каждый член класса и метод является общедоступным в Python, приводит ко второму отличию: поддержка инкапсуляции в Python намного слабее, чем в C ++.

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

Операторские перегрузки против методов Dunder

В C + вы можете добавить * перегрузки операторов *. Они позволяют вам определять поведение определенных синтаксических операторов (например, `==`) для определенных типов данных. Обычно это используется для добавления более естественного использования ваших классов. Для оператора `== +` вы можете точно определить, что означает равенство двух объектов класса.

Одно из различий, которое некоторым разработчикам требуется много времени, заключается в том, как обойти отсутствие перегрузок операторов в Python. Замечательно, что все объекты Python работают в любом из стандартных контейнеров, но что, если вы хотите, чтобы оператор== проводил глубокое сравнение между двумя объектами вашего нового класса? В C + вы должны создать в своем классе оператор `+ operator == ()` и провести сравнение.

Python имеет аналогичную структуру, которая довольно последовательно используется во всем языке:dunder methods. Методы Dunder получили свое название, потому что все они начинаются и заканчиваются двойным подчеркиванием или «d-under».

Многие встроенные функции, которые работают с объектами в Python, обрабатываются вызовамиdunder methods этого объекта. В приведенном выше примере вы можете добавить__eq__() в свой класс, чтобы делать любое интересное сравнение, которое вам нравится:

class MyFancyComparisonClass():
    def __eq__(self, other):
        return True

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

В Python используется большое количество более сложных методов, и встроенные функции широко их используют. Например, добавление__lt__() позволит Python сравнить относительный порядок двух ваших объектов. Это означает, что теперь будет работать не только оператор<, но и>,<= и>=.

Еще лучше, если у вас есть несколько объектов вашего нового класса в списке, тогда вы можете использоватьsorted() в списке, и они будут отсортированы с использованием__lt__().

Еще раз, давайте взглянем на вашу сравнительную таблицу Python против C ++:

Особенность питон C++

Более быстрое выполнение

x

Кросс-платформенное исполнение

x

Переменные одного типа

x

Переменные нескольких типов

x

постижения

x

Богатый набор встроенных алгоритмов

x

x

Статическая печать

x

Динамический набор текста

x

Строгая инкапсуляция

x

Теперь, когда вы увидели объектно-ориентированное кодирование на обоих языках, давайте посмотрим, как Python и C ++ управляют этими объектами в памяти.

Управление памятью

Когда вы сравниваете Python и C, одно из самых больших различий заключается в том, как они обрабатывают память. Как вы видели в разделе о переменных в именах C и Python, Python не имеет указателей и не позволяет напрямую управлять памятью. Хотя бывают моменты, когда вы хотите иметь такой уровень контроля, в большинстве случаев в этом нет необходимости.

Отказ от прямого контроля над областями памяти приносит несколько преимуществ. Вам не нужно беспокоиться о владении памятью или о том, что память освобождается один раз (и только один раз) после ее выделения. Вам также никогда не придется беспокоиться о том, был ли объект размещен в стеке или в куче, что может сбить с толку начинающих разработчиков C ++.

Python управляет всеми этими проблемами для вас. Для этого все в Python является производным классом отobject Python. Это позволяет интерпретатору Python осуществлять подсчет ссылок как средство отслеживания того, какие объекты все еще используются, а какие можно освободить.

Конечно, это удобство имеет свою цену. Чтобы освободить для вас выделенные объекты памяти, Python иногда потребуется запускать так называемыйgarbage collector, который находит неиспользуемые объекты памяти и освобождает их.

Note: CPython имеет сложныйmemory management scheme, что означает, что освобождение памяти не обязательно означает, что память возвращается в операционную систему.

Python использует два инструмента для освобождения памяти:

  1. Коллектор подсчета ссылок

  2. Поколение коллекционера

Давайте посмотрим на каждый из них в отдельности.

Коллектор подсчета ссылок

Сборщик подсчета ссылок является основополагающим для стандартного интерпретатора Python и всегда работает. Он работает, отслеживая, сколько раз конкретному блоку памяти (который всегда является Pythonobject) было присвоено имя во время работы вашей программы. Многие правила описывают, когда счетчик ссылок увеличивается или уменьшается, но пример одного случая может прояснить:

>>>

 1 >>> x = 'A long string'
 2 >>> y = x
 3 >>> del x
 4 >>> del y

В приведенном выше примере строка 1 создает новый объект, содержащий строку"A long string". Затем он помещает имяx на этот объект, увеличивая счетчик ссылок объекта до 1:

A Python object with reference count of one.

В строке 2 он присваиваетy имя тому же объекту, что увеличивает счетчик ссылок до 2:

A Python object with reference count of two.

Когда вы вызываетеdel сx в строке 3, вы удаляете одну из ссылок на объект, уменьшая счетчик до 1:

Two Python objects

Наконец, когда вы удаляетеy, последнюю ссылку на объект, его счетчик ссылок падает до нуля, и он может быть освобожден сборщиком мусора, подсчитывающим ссылки. Он может или не может быть освобожден немедленно в этот момент, но, как правило, это не должно иметь значения для разработчика:

The Python None object with reference count of two and another Python object with reference count of zero.

Хотя это позаботится о поиске и освобождении многих объектов, которые должны быть освобождены, есть несколько ситуаций, которые он не поймает. Для этого вам нужен сборщик мусора поколений.

Поколение сборщика мусора

Одна из больших дыр в схеме подсчета ссылок заключается в том, что ваша программа может построить цикл ссылок, где объектA имеет ссылку на объектB, который имеет обратную ссылку на объектAс. Вполне возможно попасть в такую ​​ситуацию, и в вашем коде ничего не будет упоминаться ни об одном объекте. В этом случае ни один из объектов никогда не достигнет счетчика ссылок 0.

generational garbage collector включает сложный алгоритм, который выходит за рамки этой статьи, но он найдет некоторые из этих бесхозных ссылочных циклов и освободит их для вас. Время от времени он запускается под контролем параметров, описанных вin the documentation. Один из этих параметров - полностью отключить этот сборщик мусора.

Когда ты не хочешь сбор мусора

Когда вы сравниваете Python и C, как и любые два инструмента, каждое преимущество имеет компромисс. Python не требует явного управления памятью, но иногда он тратит больше времени, чем ожидалось, на сборку мусора. Обратное верно для C: ваша программа будет иметь постоянное время отклика, но вам нужно будет приложить больше усилий для управления памятью.

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

Системы с жесткими требованиями в реальном времени являются одними из систем, для которых Python является плохим выбором языка. Наличие жестко контролируемой системы, в которой вы уверены, что выбор времени - хорошее применение C ++. Это типы вопросов, которые необходимо учитывать, когда вы выбираете язык для проекта.

Время обновить диаграмму Python против C ++:

Особенность питон C++

Более быстрое выполнение

x

Кросс-платформенное исполнение

x

Переменные одного типа

x

Переменные нескольких типов

x

постижения

x

Богатый набор встроенных алгоритмов

x

x

Статическая печать

x

Динамический набор текста

x

Строгая инкапсуляция

x

Прямое управление памятью

x

Вывоз мусора

x

Потоки, многопроцессорность и асинхронный ввод-вывод

Модели параллелизма в C ++ и Python похожи, но имеют разные результаты и преимущества. Оба языка поддерживают потоки, многопроцессорность и асинхронные операции ввода-вывода. Давайте посмотрим на каждый из них.

Многопоточность

Хотя и C, и Python имеют встроенную в язык многопоточность, результаты могут заметно отличаться в зависимости от решаемой проблемы. Часто https://realpython.com/intro-to-python-threading/[threading] используется для решения проблем с производительностью. В C многопоточность может обеспечить общее ускорение как для задач, связанных с вычислениями, так и для задач ввода-вывода, поскольку потоки могут использовать все преимущества ядер в многопроцессорной системе.

Python, с другой стороны, пошел на компромисс в дизайне, чтобы использоватьGlobal Interpreter Lock илиGIL, чтобы упростить реализацию потоковой передачи. GIL имеет много преимуществ, но недостатком является то, что в один момент времени будет работать только один поток, даже если имеется несколько ядер.

Если ваша проблема связана с вводом / выводом, например, при загрузке нескольких веб-страниц одновременно, то это ограничение вас ничуть не смущает. Вы оцените более простую модель потоков Python и встроенные методы дляinter-thread communications. Однако, если ваша проблема связана с процессором, то GIL ограничит вашу производительность одним процессором. К счастью, многопроцессорная библиотека Python имеет интерфейс, аналогичный библиотеке потоков.

многопроцессорная обработка

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

Хотя Python все еще использует похожие примитивы ОС для создания новых процессов, большая часть низкоуровневых сложностей скрыта от разработчика.

C ++ полагается наfork() для обеспечения поддержки многопроцессорности. Хотя это дает вам прямой доступ ко всем элементам управления и вопросам порождения нескольких процессов, это также намного сложнее.

Async IO

Хотя и Python, и C поддерживают процедуры асинхронного ввода-вывода, они обрабатываются по-разному. В C методыstd::async, вероятно, будут использовать потоки для достижения асинхронного характера операций ввода-вывода. В Python кодAsync IO будет выполняться только в одном потоке.

Здесь есть и компромиссы. Использование отдельных потоков позволяет коду асинхронного ввода-вывода C ++ быстрее выполнять задачи, связанные с вычислениями. Задачи Python, используемые в его реализации Async IO, более легки, поэтому их быстрее раскручивать для решения проблем, связанных с вводом / выводом.

Ваша таблица сравнения Python против C ++ остается неизменной для этого раздела. Оба языка поддерживают полный спектр вариантов параллелизма с различными компромиссами между скоростью и удобством.

Разные проблемы

Если вы сравниваете Python с C ++ и смотрите на добавление Python в ваш инструментарий, то есть еще несколько вещей, которые следует учитывать. Хотя ваш текущий редактор или IDE, безусловно, будет работать для Python, вы можете добавить определенные расширения или языковые пакеты. Также стоит взглянуть наPyCharm, поскольку он специфичен для Python.

Несколько проектов C ++ имеют привязки Python. Такие вещи, какQt,WxWidgets и многие API обмена сообщениями, имеющие многоязычные привязки.

Если вы хотитеembed Python in C++, вы можете использоватьPython/C API.

Наконец, есть несколько методов использования ваших навыков C для расширения Python и добавления функций или для вызова существующих библиотек C из вашего кода Python. Такие инструменты, какCTypes,Cython,CFFI,Boost.Python иSwig, могут помочь вам комбинировать эти языки и использовать каждый для того, что у него получается лучше всего.

Резюме: Python против C ++

Вы потратили некоторое время на чтение и размышления о различиях между Python и C ++. Хотя Python имеет более простой синтаксис и меньше острых углов, он не идеально подходит для всех задач. Вы рассмотрели синтаксис, управление памятью, обработку и некоторые другие аспекты этих двух языков.

Давайте вкратце рассмотрим сравнительную таблицу Python и C ++:

Особенность питон C++

Более быстрое выполнение

x

Кросс-платформенное исполнение

x

Переменные одного типа

x

Переменные нескольких типов

x

постижения

x

Богатый набор встроенных алгоритмов

x

x

Статическая печать

x

Динамический набор текста

x

Строгая инкапсуляция

x

Прямое управление памятью

x

Вывоз мусора

x

Если вы сравниваете Python с C ++, то из диаграммы вы можете видеть, что это не тот случай, когда один лучше другого. Каждый из них представляет собой инструмент, который хорошо разработан для различных вариантов использования. Так же, как вы не используете молоток для ввинчивания винтов, использование правильного языка для работы сделает вашу жизнь проще!

Заключение

Congrats! Теперь вы видели некоторые сильные и слабые стороны Python и C ++. Вы узнали о некоторых особенностях каждого языка и о том, как они похожи.

Вы видели, что C ++ великолепен, когда вы хотите:

  • Быстрая скорость выполнения (потенциально за счет скорости разработки)

  • Полный контроль над памятью

И наоборот, Python великолепен, когда вы хотите:

  • Быстрая скорость разработки (потенциально за счет скорости выполнения)

  • Управляемая память

Теперь вы готовы сделать правильный выбор языка, когда речь заходит о вашем следующем проекте!