Укр
Java против Python: основы Python для Java разработчиков

Java против Python: основы Python для Java разработчиков

  • 30 мая, 2022
  • читать 20 мин

Это перевод статьи Яна-Хайна Бюрмана на сайте Real Python.

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

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

История Python

Python — это язык программирования, разработанный программистом Гвидо ван Россумом. Он искал, чем бы заняться во время рождественских праздников 1989 года, и именно тогда он начал разработку интерпретатора Python.

Python основывается на таких языках: ABC, C и Modula-3. По сути, это объектно-ориентированный императивный язык программирования.

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

В начале 2021 года TIOBE в четвертый раз объявила Python языком программирования года. Согласно отчету Octoverse за 2021 год, Python занимает второе место среди самых популярных языков на GitHub среди участников репозитория.

Какова философия Python?

Некоторые идеи, лежащие в основе Java и Python, схожи, но каждый язык программирования имеет свои уникальные характеристики.

Философия Python представлена ​​в виде набора девятнадцати руководящих принципов, Zen of Python.

А еще в Python есть несколько пасхалок — вот, что происходит, когда вы вводите следующую команду в цикле чтения-оценки-печати Python (REPL):

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

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

Код Python читаем

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

Этому есть причины:

  • Отступ используется для группировки операторов. Это делает блоки кода короче и способствует единому стилю кодирования.
  • Несколько встроенных высокоуровневых структур данных в сочетании со скромным набором символов операторов делают Python очень выразительным.
  • Выбор использования исключений в качестве основного способа обработки ошибок обеспечивает чистоту кода.
  • Программисты Python предпочитают стиль, вдохновленный концепцией «Легче попросить прощения, чем разрешения» (EAFP), а не концепцией «Посмотри, прежде чем прыгнуть» (LBYL).

Python включает в себя стандартную библиотеку

Цель Python состоит в том, чтобы решить большинство повседневных проблем, используя только стандартный дистрибутив Python.

Поэтому у Python есть стандартная библиотека. Как и библиотека классов Java, это обширная коллекция полезных средств, состоящая из констант, функций, классов и фреймворков.

Python продвигает идею повторного использования кода

В Python есть несколько функций для разработки кода, который можно повторно использовать в разных местах согласно принципу «Не повторяйся» (DRY).

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

Другой метод, который можно использовать в Python, — это объектно-ориентированное программирование.

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

Python легко расширяется

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

Самый простой способ расширить Python — написать код на чистом Python. Вы также можете определять модули, используя привязки на упрощенном диалекте Python, называемом Cython, а еще на C или C++.

Как начать знакомство с Python?

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

Как Java-разработчик, вы, возможно, помните свои первые шаги по изучению Java и установке вашего первого Java Development Kit.

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

Установка Python

Первый шаг — установить последнюю версию Python. Для этого следуйте этому руководству по установке и настройке Python 3.

Еще одно место, где вы можете найти инструкции по установке, — это официальная страница загрузки Python.

Примечание. Убедитесь, что у вас установлена ​​последняя версия Python. На момент написания этого руководства самой последней версией является последняя версия исправления серии 3.10.x. Фрагменты кода, показанные в этом руководстве, должны работать с этой версией Python.

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

В таких ситуациях удобно иметь доступ к нескольким версиям Python на одном компьютере. Инструмент, обеспечивающий эту функциональность, pyenv, сравним с jEnv в Java.

Создание песочницы и ее использование

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

Хотя Python поставляется с обширной стандартной библиотекой со всевозможными функциями, еще больше возможностей доступно в виде внешних пакетов, подавляющее большинство которых имеют открытый исходный код. Индекс пакетов Python, или сокращенно PyPI, является основным центральным репозиторием, который собирает и предоставляет эти пакеты. Вы можете установить пакеты с помощью команды pip.

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

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

Выбор редактора или интегрированной среды разработки

Решите, какой редактор или IDE вы хотите использовать. Если вы привыкли к IntelliJ, то PyCharm кажется логичным выбором, поскольку он принадлежит к той же линейке продуктов. Еще одним популярным редактором является Visual Studio Code, но вы также можете выбирать из многих других вариантов.

После установки Python и внешних пакетов в виртуальную среду, а также выбора редактора или IDE, вы можете начать экспериментировать с языком.

Чем Python отличается от Java?

В следующих подразделах вы познакомитесь с наиболее важными отличиями Python от Java.

Отступ для группировки блоков кода

Возможно, наиболее яркой особенностью Python является его синтаксис.

Указание его функций, классов, конструкций управления потоком и блоков кода сильно отличается от того, к чему вы привыкли. В Java вы указываете блоки кода с помощью известных фигурных скобок ({ and }). Однако в Python блоки кода указываются уровнем отступа.

Здесь вы видите пример, демонстрирующий, как отступ определяет группировку блоков кода:

def parity(number):
    result = "odd"                              # Function body
    if number % 2 == 0:
        result = "even"                         # Body of if-block
    return result                               # Not part of if-block

for num in range(4):                            # Not part of function
    print("Number", num, "is", parity(num))     # Body of for-loop
print("This is not part of the loop")           # Not part of for-loop

Код отображает несколько новых концепций:

  • Строка 1: оператор def начинает определение новой функции с названием parity(), которая принимает аргумент с именем number. Обратите внимание, что если бы оператор def появился бы в блоке определения класса, вместо этого он запустил бы определение метода.
  • Строка 2: Внутри parity() тело функции начинается на уровне с отступом. Первый оператор — это присвоение строки "odd" переменной result.
  • Строка 3: Здесь вы видите начало оператора if.
  • Строка 4: Дополнительный отступ начинает новый блок. Этот блок выполняется, когда условное выражение оператора number % 2 == 0 оценивается как истинное. В примере он состоит только из одной строки, в которой вы присваиваете значение "even" переменной result.
  • Строка 5: Отступ, предшествующий оператору return, отмечает конец оператора if и связанного с ним блока.
  • Строка 7: Точно так же вы видите отступ, который предшествует началу цикла for. Следовательно, цикл for начинается с того же уровня отступа, что и начало блока определения функции в первой строке. Он отмечает конец блока определения функции.
  • Строка 8: Вы видите, что то же самое снова происходит внутри цикла for. Первый вызов функции print() является частью блока цикла for.
  • Строка 9: Этот второй вызов функции print() с отступом не является частью блока цикла for.

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

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

Наконец, вы, вероятно, также заметили, что для комментариев можно использовать знак решетки #.

Этот пример кода приведет к следующему выводу:

Number 0 is even
Number 1 is odd
Number 2 is even
Number 3 is odd
This is not part of the loop

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

Есть полезное руководство по стилю кода Python под названием PEP 8.

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

Примечание. Руководство по стилю является примером предложения по улучшению Python, или сокращенно PEP. PEP не только содержат предложения, но и отражают спецификации для реализации, так что вы можете сравнить PEP с объединением JEP и JSR в Java. PEP 0 перечисляет индекс PEP.

В PEP 8 можно найти много интересной информации, включая соглашения об именах Python, они немного отличаются от Java.

Цикл чтения-оценки-печати с самого начала

С самого начала Python всегда имел встроенный цикл чтения-оценки-печати (REPL). REPL считывает максимально короткий полный оператор, выражение или блок, компилирует его в байт-код и выполняет его оценку. Если оцениваемый код возвращает объект, отличный от объекта None, он выводит однозначное представление этого объекта.

Примечание. Вы можете сравнить Python REPL с Java JShell (JEP 222), который доступен с JDK 9.

Следующий фрагмент показывает, как работает Python REPL:

>>> zero = int(0)
>>> zero
0
>>> float(zero)
0.0
>>> complex(zero)
0j
>>> bool(zero)
False
>>> str(zero)
'0'

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

Разница между Java и Python заключается в операторе присваивания (=). Обычное присваивание Python, в котором используется один знак равенства, представляет собой оператор, а не выражение, которое выдает какое-то значение или объект.

Это объясняет, почему REPL не отображает присвоение переменной zero: операторы всегда оцениваются как None. Строка, следующая за присваиванием, содержит выражение переменной, zero, чтобы указать REPL отображать переменную в любом случае.

Примечание. В Python 3.8 появился оператор выражения присваивания ( :=), также известный как оператор «морж». Он присваивает значения переменным, но, в отличие от обычного присваивания, вычисляет их как в выражении. Это похоже на оператор присваивания в Java.

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

В REPL специальная переменная подчеркивания (_) содержит значение последнего выражения, если оно не None. Следующий фрагмент показывает, как вы можете использовать эту специальную переменную:

>>> 2 + 2
4
>>> _
4
>>> _ + 2
6
>>> some_var = _ + 1
>>> _
6
>>> some_var
7

После того, как вы присвоите значение some_var, специальная переменная _ по-прежнему будет хранить значение 6. Это потому, что оператор присваивания оценивается как None.

Динамически типизированный и строго типизированный

Важной характеристикой языка программирования является то, когда, как и в какой степени интерпретатор языка или компилятор выполняет проверку типов.

Python — это язык с динамической типизацией. Это означает, что типы переменных, параметры функций и возвращаемые значения функций проверяются во время выполнения, а не во время компиляции, в отличие от Java.

Python в то же время является строго типизированным языком:

  • Каждый объект имеет определенный тип, связанный с ним
  • Необходимо явное преобразование между несовместимыми типами

Вот так Python проверяет совместимость типов во время выполнения и делает типы совместимыми:

>>> 40 + "2"
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> 40 + int("2")  # Add two numbers
42
>>> str(40) + "2"  # Concatenate strings
'402'
>>> 40 * "2"       # Repeat string "2" forty times
'2222222222222222222222222222222222222222'

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

Чтобы решить эту проблему, вы конвертируете один тип в другой. Если вы хотите сложить два объекта вместе как числа, вы преобразуете строку, представляющую число, в простое число с помощью конструктора int(). Если вместо этого вы хотите объединить два объекта в виде строк, вы преобразуете число в строку с помощью конструктора str().

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

Хотя Python — это язык с динамической типизацией, в код можно добавить аннотации типов.

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

Примечание. Как указано выше, среда выполнения Python делает аннотации типов доступными для самоанализа кода. Некоторые библиотеки используют эту информацию, например, FastAPI.

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

CPython против компилятора JIT

В отличие от Java, эталонная реализация CPython не имеет JIT-компилятора. CPython — это компилятор и интерпретатор, написанный на C и доступный практически на всех платформах.

CPython загружает исходный файл, который называется модулем, в два этапа:

  1. Компиляция: сначала CPython считывает код и компилирует его в байт-код, представляющий собой последовательность инструкций, которую может выполнить интерпретатор байт-кода CPython. В некоторой степени вы можете сравнить фазу компиляции с тем, как javac компилирует файл .java в файл .class.
  2. Выполнение: Интерпретатор байт-кода CPython, другими словами, виртуальная машина (ВМ) CPython, последовательно выполняет байт-код из первого шага.

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

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

В отличие от основных реализаций Java VM, CPython не компилирует впоследствии байт-код в собственный объектный код. Однако есть и другие реализации Python, которые работают по-другому:

  • Существует реализация Python для Java под названием Jython. Он работает в JVM, и существует прямая совместимость между Java и Python.
  • Кроме того, существует версия под названием IronPython, работающая на платформе .NET.
  • Существует реализация, использующая компилятор Just-in-Time (JIT), под названием PyPy. В среднем PyPy в 4,2 раза быстрее, чем CPython.
  • Наконец, GraalVM — это высокопроизводительная среда выполнения, поддерживающая множество языков программирования. Она обеспечивает экспериментальную поддержку относительно недавней версии Python.

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

Встроенная функция и перегрузка оператора

Как разработчик Java, вы можете знать термин перегрузка из-за перегрузки методов.

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

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

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

Python предоставляет доступный способ достижения перегрузки функций и операторов.

Вы можете попробовать его, определив в своем классе методы со специальными именами. Имя такого метода начинается и заканчивается двумя символами подчеркивания, например .__len__() или .__add__(). Идентификатор с таким именем называется дандер, сокращение от двойного подчеркивания (__).

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

Например, вы можете определить .__len__() поведение встроенной функции len(). Точно так же вы можете задать поведение .__add__() для оператора сложения (+).

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

Хороший синтаксис для функциональной обработки коллекций

В Java вы могли создавать списки, комбинируя вызовы map(), filter() и лямбда-выражений. Вы можете сделать то же самое в Python, используя те же функции и методы, хотя использование этих конструкций часто усложняет код.

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

Все является объектом

В Java не все является объектом, несмотря на то, что код можно поместить только внутри класса Java. Например, примитив Java 42 не является объектом.

Как и Java, Python также полностью поддерживает объектно-ориентированный стиль программирования. Отличие от Java в том, что в Python все является объектом. Некоторые примеры объектов Python:

Поскольку они являются объектами, вы можете хранить все это в переменных, передавать их и анализировать во время выполнения.

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

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

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

Они позволяют вам создавать собственную программируемую вселенную дополнительного или альтернативного поведения классов и экземпляров.

Какие аспекты Java и Python схожи?

Несмотря на различия, вы, вероятно, уже заметили некоторое сходство между Java и Python. Это потому, что и Python, и Java основываются на языке C.

Ориентация объектов на основе классов

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

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

Вы также можете ознакомиться с обзором объектно-ориентированного программирования в Python 3, чтобы расширить свои знания по этой теме.

Операторы

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

Для начала сравните известные арифметические операторы в Java и Python.

Оператор сложения (+), оператор вычитания (-), оператор умножения (*), оператор деления (/) и оператор по модулю (%) имеют почти одинаковое предназначение в обоих языках, за исключением оператора деления для целочисленных операндов.

То же самое относится и к побитовым операторам: побитовому оператору OR (|), побитовому оператору AND (&), побитовому оператору XOR (^) и унарному побитовому оператору NOT (~), а также к операторам побитового сдвига для сдвига влево (<<) и сдвиг вправо (>>).

Вы можете использовать синтаксис квадратных скобок ([]) в Python для доступа к элементу последовательности точно так же, как вы можете работать с доступом к массиву в Java.

Форматирование строк

Первоначально Python использовал функции форматирования строк, основанные на том, как семейство функций printf обрабатывает их в языке программирования C.

Это похоже на Java String.format(). В Python эту функцию "%" выполняет оператор. Левая часть оператора содержит строку формата, а правая часть содержит либо кортеж позиционных параметров, либо словарь ключевых параметров.

Вот пример:

>>> "Hello, %s!" % "world"             # %-style, single argument
'Hello, world!'
>>> "The %s is %d." % ("answer", 42)   # %-style, positional
'The answer is 42.'
>>> "The %(word)s is %(value)d." \
... % dict(word="answer", value=42)    # %-style, key-based
'The answer is 42.'

Совсем недавно Python принял другие способы форматирования строк.

Один из них заключается в использовании строкового метода .format(), в котором замещающие поля обозначаются фигурными скобками ({}). Примером этого является "The {word} is {value}.".format(word="answer", value=42).

Начиная с Python 3.6, вы также можете использовать форматированные строковые литералы, также известные как f-строки.

Предположим, у вас есть две переменные в области видимости с именами word и value. В этом случае выражение f"The {word} is {value}." отображает для вас ту же строку, что и в .format() в приведенном выше примере.

Конструкции потока управления

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

Цикл Python while похож на цикл Java:

while (word := input("Enter word: ")) != "END":
    print(word)

print("READY")

Фрагмент кода строка за строкой копирует стандартный ввод в стандартный вывод, пока строка не станет равной "END". Эта строка не копируется, "READY" вместо этого записывается текст, за которым следует новая строка.

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

Примечание. В Python нет конструкции цикла do {...} while (...)

Цикл Python for похож на цикл for-each в Java.

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

>>> roman_numerals = "I II III IV V".split()
>>> roman_numerals
['I', 'II', 'III', 'IV', 'V']
>>> for numeral in roman_numerals:
...     print(numeral)
...
I
II
III
IV
V

Использование str.split() — это удобный способ создать список слов.

Примечание. Таким образом можно выполнять итерацию не только по экземпляру list, но и по любому итерируемому объекту.

Иногда вместо этого вам может понадобиться счетчик пробега. В этом случае вы должны использовать range():

>>> for i in range(5):
...     print(i)
...
0
1
2
3
4

В этом примере i ссылается на следующее значение запрошенного диапазона при каждой итерации. Это значение впоследствии печатается.

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

>>> for i, numeral in enumerate("I II III IV V".split(), start=1):
...     print(i, numeral)
...
1 I
2 II
3 III
4 IV
5 V

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

Python также понимает операторы break и continue.

Другой конструкцией потока управления, похожей на Java, является оператор if:

>>> for n in range(3):
...     if n <= 0:
...         adjective = "not enough"
...     elif n == 1:
...         adjective = "just enough"
...     else:
...         adjective = "more than enough"
...     print(f"You have {adjective} items ({n:d})")
...
You have not enough items (0)
You have just enough items (1)
You have more than enough items (2)

Как было продемонстрировано выше, конструкция Python if ... else также поддерживает ключевое слово elif, что полезно, поскольку здесь нет простого оператора switch ... case.

Примечание. Недавно выпущенная версия Python 3.10 содержит новую функцию под названием структурное сопоставление с образцом, которая вводит ключевые слова match и case, но ведет себя совершенно иначе, чем оператор switch в Java.

Эта новая языковая функция вдохновлена ​​оператором сопоставления с образцом в Scala, еще одном языке программирования, работающем на JVM.

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

Например, циклы Python, а также конструкции перехвата исключений поддерживают часть else:. Кроме того, Python предоставляет оператор with для менеджеров контекста.

Java против Python: что такое нативные типы данных высокого уровня?

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

Числовые типы и их операторы

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

Если вы сравните оба языка, то обнаружите, что целые числа Python могут содержать произвольные длинные значения, ограниченные только объемом (виртуальной) памяти, доступной на вашей машине. Вы можете думать о них как об разумной смеси собственных целых чисел фиксированной точности — или примитивных целых типов, как их называет Java — и BigInteger чисел Java со следующими последствиями:

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

Используя префиксы 0x, 0o, и 0b, вы можете указывать целые числа Python как шестнадцатеричные, восьмеричные и двоичные константы соответственно.

Примечание. Это означает, что восьмеричные числа не имеют префикса с одним или несколькими начальными нулями (0), что отличается от Java.

Известные арифметические операторы +, -, *, / и % в Java и Python имеют одинаковое значение в обоих языках, за исключением оператора деления для целочисленных типов.

Оператор truediv (/), примененный к операндам int, дает значение float в Python, которое отличается от Java. Python имеет оператор floordiv (//) для деления, который округляет до ближайшего целого числа, сравнимого с оператором деления (/) в Java:

>>> 11 / 4          # truediv
2.75
>>> 11.0 // 4       # floordiv, despite float operand(s)
2.0

Кроме того, Python предоставляет оператор двойной звездочки (**) для возведения в степень в качестве альтернативы функции с двумя аргументами pow(). Оператор matmul (@) зарезервирован как дополнительный оператор для типов, предоставляемых внешними пакетами, предназначенный для удобства обозначения умножения матриц.

И Python, и Java переняли побитовые операторы из языка программирования C. Это означает, что побитовые операторы (|, &, ^ и унарные ~) имеют одинаковое значение в обоих языках программирования.

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

Это означает, что концептуально отрицательные значения имеют бесконечное количество начальных 1 битов, точно так же, как концептуально положительные числа имеют бесконечное количество начальных 0 битов:

>>> bin(~0)
'-0b1'
>>> bin(~0 & 0b1111)       # ~0 is an "infinite" sequence of ones
'0b1111'

Фрагмент кода выше показывает, что независимо от выбранного вами значения, если вы выполняете побитовое AND с этим значением с константой ~0, то значение равно выбранному значению. Это означает, что константа ~0 концептуально представляет собой бесконечную последовательность 1 битов.

Также доступны операторы битового сдвига (<< and >>). Однако эквивалента побитового оператора сдвига вправо с заполнением нулями (>>>) в Java не существует, поскольку он не имеет смысла в системе счисления с произвольными длинными целыми числами. В пределах досягаемости нет самого значимого бита. Другое различие между обоими языками заключается в том, что Python не позволяет сдвигать биты с отрицательным числом сдвигов.

Стандартная библиотека Python также предоставляет другие числовые типы. Есть десятичная арифметика decimal.Decimal с фиксированной и плавающей запятой, которая сравнима с Java BigDecimal.

Существует класс fractions.Fraction для рациональных чисел, который сравним с Apache Commons Math Fractions. Обратите внимание, что эти типы не классифицируются как встроенные числовые типы.

Основные типы последовательностей

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

Python имеет три встроенных основных типа последовательностей:

Как видите, синтаксическая разница между инициализаторами списка и кортежа заключается в квадратных скобках ([]) и круглых скобках (()).

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

Кортеж, с другой стороны, больше похож на неизменяемую версию Pair-подобного класса в Java, за исключением произвольного количества записей вместо двух. Пустые скобки (()) обозначают пустой кортеж. Конструкция like (3,) обозначает кортеж, содержащий один элемент. В этом случае единственным элементом является 3.

Диапазон дает последовательность чисел, которую вы обычно используете в циклах.Вы видели пример этого ранее в руководстве.

Чтобы выбрать элемент из последовательности, вы можете указать отсчитываемый от нуля индекс в квадратных скобках, как в some_sequence[some_index]. Отрицательные индексы отсчитываются в обратном порядке от конца, поэтому -1 обозначают последний элемент.

Вы также можете выбрать фрагмент из последовательности. Это выбор нуля, одного или нескольких элементов, дающий объект того же типа, что и исходная последовательность. Вы можете указать значение start, stop и step, также известное как шаг. Примером синтаксиса нарезки является some_sequence[<start>:<stop>:<step>].

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

Для положительных индексов синтаксис Python похож на то, как вы выбираете элементы в массивах Java.

Вы можете объединить большинство последовательностей с помощью оператора со знаком плюс (+) и повторить их с помощью оператора звездочки (*):

>>> ["testing"] + ["one", "two"] * 2
['testing', 'one', 'two', 'one', 'two']

Вы не можете выполнить конкатенацию или повторение последовательности с диапазонами, но вы можете их разрезать. Например, попробуйте range(6, 36, 3)[7:2:-2] и подумайте, что у вас получится в результате.

Словари

Словарь dict в Python похож на словарь Java LinkedHashMap. Синтаксис константы инициализатора dict представляет собой последовательность разделенных запятыми записей key: value между фигурными скобками ({}). Примером этого является {"pi": 3.14, "e": 2.71}.

Чтобы выбрать элемент из словаря или любого другого сопоставления, вы можете указать ключ в квадратных скобках ([]), как в math_symbols["pi"]. И ключи, и значения могут быть любыми объектами, но ключи должны быть хешируемыми, что означает, что они обычно неизменяемы или, по крайней мере, должны вести себя как неизменяемые объекты. Ключи не обязательно должны быть одного типа, хотя обычно это так. То же самое относится и к ценностям.

Наборы

Python также предоставляет наборы. Вы можете инициализировать набор с помощью синтаксиса, подобного {"pi", "e"}, или используя синтаксис конструктора set(), используя итерируемый объект в качестве аргумента. Чтобы создать пустой набор, вы используете выражение set(), так как литерал {} уже был передан словарям.

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

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

Строки

Как и в Java, строки в Python представляют собой неизменяемые последовательности элементов Unicode. Строковые литералы указываются между двойными кавычками ("), или вы также можете указать их между одинарными кавычками ('), что отличается от Java.

Два примера строк: "foo"и 'bar'. Различные кавычки не обязательно имеют разное значение при определении строки. Однако следует отметить, что если вы используете какие-либо кавычки как часть строки, вам придется экранировать их, если они также являются разделителями строки.

Как и в Java, обратная косая черта (\) в Python — это символ, который вводит управляющую последовательность. Интерпретатор Python распознает escape-последовательности, также известные в Java, такие как \b, \n, \t и несколько дополнительных из языка программирования C.

По умолчанию Python использует кодировку UTF-8 для ваших исходных файлов Python. Это означает, что вы можете поместить литерал Unicode непосредственно в строку, как в случае с "é". Вы также можете использовать 16- или 32-битное шестнадцатеричное представление его кодовой точки. Для "é", вы бы сделали это, используя escape-последовательности \u00E9 или \U000000E9. Обратите внимание на разницу между строчными \u и прописными \U escape-последовательностями. Наконец, также можно указать его описание в формате Unicode, например, \N{Latin Small Letter E with acute}.

Вы можете использовать символы Unicode даже в идентификаторах Python, но тогда возникает вопрос, целесообразно ли это делать.

Если вы ставите перед строкой префикс r, например r"raw\text", обратная косая черта теряет свое особое значение. Это особенно удобно, когда вы хотите указать регулярные выражения.

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

>>> s = """This is a
...        multiline
...        string.
...        """
...
>>> for line in s.splitlines():
...     print(repr(line))
...
'This is a'
'       multiline'
'       string.'
'       '

Вы можете сравнить этот тип строки с текстовыми блоками Java (JEP 378), хотя и с другими синтаксическими ограничениями и с другим сохранением пробелов (табуляции, пробелы и символы новой строки).

Байты

В Java, если вам нужно хранить двоичные данные, а не текст, вы, вероятно, использовали бы ByteBuffer, что дает вам изменяемые объекты. В Python объекты bytearray предоставляют аналогичную функциональность.

В отличие от Java, Python также предлагает тип bytes для хранения неизменяемых двоичных данных. Байтовые литералы очень похожи на строковые литералы, за исключением того, что перед литералом ставится префикс b.

Строки содержат .encode() метод для преобразования их в последовательность байтов, а объект bytes содержит метод .decode() для преобразования в строку:

>>> bytes(4)                     # Zero-filled with a specified length
b'\x00\x00\x00\x00'
>>> bytes(range(4))              # From an iterable of integers
b'\x00\x01\x02\x03'
>>> b = "Attaché case".encode()  # Many different codecs are available
>>> b
b'Attach\xc3\xa9 case'
>>> b.decode()                   # Decode back into a string again
'Attaché case'

Если кодек не указан, для кодирования строк и декодирования байтов используется кодек UTF-8 по умолчанию. Когда вам нужно, вы можете выбрать из большого списка кодеков, которые обеспечивают все виды преобразования текста и байтов.

Объекты bytes в Python также имеют метод .hex(), который создает строку, в которой содержимое будет отображаться в шестнадцатеричном виде. Для обратной операции вы можете использовать метод класса .fromhex() для создания объекта bytes из шестнадцатеричного строкового представления.

Логические операторы

False и True являются двумя объектами-экземплярами bool в Python. В числовом контексте оценивается True до 1 и False до 0. Это означает, что True + True оценивается как 2.

Логические операторы в Python отличаются от операторов &&, || и ! в Java. В Python это зарезервированные ключевые слова and, or и not.

Вы видите это обобщенно в таблице ниже:

Как и в Java, существует короткое замыкание при оценке логических операторов and и or, когда интерпретатор Python оценивает операнды слева направо, пока не сможет определить истинность всего выражения.

Еще одно сходство с Java заключается в том, что интерпретатор возвращает в качестве результата последнее вычисленное подвыражение. Следовательно, вы должны знать, что результат выражения and или or не обязательно дает объект-экземпляр bool.

Все объекты Python имеют либо ложное, либо истинное значение.

Другими словами, когда вы конвертируете объекты Python в bool, результат четко определен:

  • Числовые значения, равные 0, преобразовываются в False и в True
  • Пустые контейнеры, коллекции, строки и байтовые объекты преобразуются в объекты False и True
  • Объект None также преобразуется в False
  • Все остальные объекты оцениваются как True

Примечание. Определенные пользователем классы могут предоставлять метод dunder .__bool__() для определения достоверности экземпляров своего класса.

Если вы хотите проверить, является ли контейнер или строка непустой, вы просто предоставляете этот объект в логическом контексте. Это считается питоническим подходом.

Ознакомьтесь со следующими различными способами проверки непустой строки:

>>> s = "some string"
>>> if s != "":                 # Comparing two strings
...     print('s != ""')
...
s != ""

>>> if len(s) != 0:             # Asking for the string length
...     print("len(s) != 0")
...
len(s) != 0

>>> if len(s):                  # Close, but no cigar
...     print("len(s)")
...
len(s)

>>> if s:                       # Pythonic code!
...     print("s")
...
s

В последнем примере вы просто предоставляете строку в логическом контексте. Если строка не пуста, она оценивается как истина.

Примечание. Вышеизложенное не означает, что Pythonic использует неявное преобразование bool для всех видов типов. Раздел ниже None посвящен этому более подробно.

Вы можете следовать пути обучения Write More Pythonic Code, если хотите узнать больше о наиболее типичных конструкциях Python.

В Python вы кодируете условное выражение, написанное на Java с условным оператором (? :) , как выражение с ключевыми словами if и else:

Рассмотрим пример такого типа выражения в Python:

>>> for n in range(3):
...     word = "item" if n == 1 else "items"
...     print(f"Amount: {n:d} {word}")
...
Amount: 0 items
Amount: 1 item
Amount: 2 items

REPL выводит "item" только тогда, когда n равно 1. Во всех остальных случаях REPL выводит "items".

None

В Python None — это одноэлементный объект, который можно использовать для идентификации нулевых значений. В Java вы бы использовали литерал null для аналогичных целей.

Наиболее часто None в Python используется в качестве значения параметра по умолчанию в определениях функций или методов. Кроме того, функции или методы, которые не возвращают никакого значения, на самом деле неявно возвращают объект None.

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

Следовательно, если вы хотите проверить, действительно ли объект является объектом None, вы должны сделать это явно.

Поскольку есть только один объект None, вы можете сделать это, используя оператор идентификации объекта is или противоположный оператор is not:

>>> some_value = "All" or None

>>> if some_value is None:
...     print(f"is None: {some_value}")

>>> if some_value is not None:
...     print(f"is not None: {some_value}")
...
is not None: All

Имейте в виду, что слово not здесь является неотъемлемой частью оператора is not и, в частности, отличается от логического оператора not.

В этом примере строка "All" имеет истинное значение в логическом контексте. Вы также можете вспомнить, что оператор or ведет себя как короткое замыкание и просто возвращает последнее выражение, как только результат становится известен, как в данном случае "All".

Другие типы данных контейнера

Java предлагает свои стандартные типы контейнеров через свою структуру коллекций.

Python использует другой подход. Он предлагает базовые типы контейнеров, которые вы исследовали ранее в этом разделе, как встроенные типы, а затем стандартная библиотека Python предоставляет еще несколько типов данных контейнеров через модуль collections. Есть много полезных примеров типов контейнеров, к которым вы можете получить доступ через модуль collections:

  • namedtuple предоставляет кортежи, в которых вы также можете получить доступ к элементам через имена полей
  • deque обеспечивает двусторонние очереди с быстрым добавлением и удалением на обоих концах коллекции
  • ChainMap позволяет свернуть несколько объектов сопоставления в один вид на сопоставлении
  • Counter обеспечивает сопоставление для подсчета хешируемых объектов
  • defaultdict предоставляет сопоставление, которое вызывает фабричную функцию для предоставления отсутствующих значений

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

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

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

Полезные и популярные библиотеки или фреймворки Python

Вы можете использовать Python во многих областях. Ниже вы найдете некоторые из этих областей вместе с их наиболее полезными и популярными библиотеками или фреймворками Python:

Сценарии командной строки: argparse предоставляет функциональные возможности для создания анализатора аргументов командной строки.

Веб-фреймворки:

  • Django предлагает немного более компактный подход, когда дело доходит до разработки полных и потенциально сложных веб-сайтов. Он включает в себя возможность определять модели, предлагает собственное решение ORM и предоставляет полный набор функций администратора. Вы можете добавить дополнительные плагины для дальнейшего расширения админки.
  • Flask позиционирует себя как микрофреймворк, который хорошо справляется с одной задачей — обслуживанием веб-запросов. Вы можете комбинировать эту основную функциональность с другими уже существующими компонентами по вашему выбору, такими как ORM и проверка формы. Многие расширения, известные как плагины Flask, доступны для удобной интеграции этих компонентов.
  • Requests делают отправку HTTP-запросов чрезвычайно удобной.

Моделирование и анализ данных: pandas, основанный на NumPy, — это быстрый, мощный, гибкий и простой инструмент для анализа и обработки данных с открытым исходным кодом. Некоторые называют панд «программируемой электронной таблицей на стероидах».

Машинное обучение: TensorFlow, Keras и PyTorch — несколько популярных фреймворков в области машинного обучения.

Наборы инструментов SQL и объектно-реляционные преобразователи (ORM): SQLAlchemy — очень популярный набор инструментов Python SQL и структура ORM.

Распределение рабочей нагрузки: Celery — это распределенная система очереди задач.

В Python также есть несколько заслуживающих внимания инструментов, связанных с обеспечением качества :

  • pytest — отличная альтернатива стандартной библиотеке unittest.
  • behave — это популярный инструмент разработки, основанный на поведении (BDD) . Вы можете комбинировать его с PyHamcrest для более выразительных проверок утверждений.
  • Flake8 — это программа для проверки руководства по стилю написания кода.
  • Pylint — это инструмент, который проверяет наличие ошибок в коде Python и выявляет стандартные отклонения кодирования.
  • Black — бескомпромиссный, трудно настраиваемый реформатор кода. Хотя он может показаться ужасным, на самом деле это отличный инструмент для любого крупномасштабного программного проекта.
  • mypy — наиболее широко используемая программа проверки статических типов.
  • Bandit находит распространенные проблемы с безопасностью.
  • Safety проверяет установленные зависимости на наличие известных уязвимостей.
  • tox — это инструмент командной строки, который помогает запускать автоматические тесты и проверки инструментов QA, определенные для вашего проекта, с помощью одной команды, а также для нескольких версий Python и конфигураций зависимостей.

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

Когда Python будет полезнее Java и почему?

Часто выбирают язык программирования для одного набора задач и другой язык программирования — для другого.

При сравнении Java и Python следует учитывать следующие аспекты:

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

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

Вывод

В этом руководстве вы познакомились с Python и получили четкое представление о свойствах этого языка программирования. Вы изучили сходства и различия между Java и Python.

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

А подтянуть свою Java можно на курсах Java.

Удачного кода!

Рекомендуем курс по теме