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

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

1. Логические операторы: and, or 

При создании инструкции if…else… мы передаем проверяемое условие. Если условие оценивается как True, выполняется блок if. В случае же его вычисления как False, запускается блок else.

Если условие содержит несколько компонентов, то для их соединения необходимы логические операторы and и or. Понятно, что истинность условия and достигается при истинности всех отдельных компонентов, тогда как условие or считается истинным в случаем истинности хотя бы одного из них. 

Такие составные условия вычисляются напрямую, вследствие чего их можно использовать как тернарные выражения. Рассмотрим примеры: 

>>> number = 5 or 4
>>> number
5
>>> text = "" or "Hello, World!"
>>> text
'Hello, World!'

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

empty_string = ""
empty_list = []
what = empty_string or empty_list

При выполнении этих строк кода вы обнаружите, что what окажется empty_list. Обсудим это позже, а пока обратимся к примерам с логическим оператором and и посмотрим, насколько они вам понятны:

>>> number1 = 3 and 5
>>> number1
5
>>> text1 = "Hello" and "" and "World"
>>> text1
''
>>> text2 = "Hello" and "World" and "!"
>>> text2
'!'

В Python такие составные условные инструкции следуют правилу сокращенных вычислений. В случае с операцией and поиск будет направлен на первое ложное значение. При обнаружении такового вычисление прекращается, а само ложное значение возвращается, как например переменная text1 в вышеуказанном фрагменте кода. Если же такое значение не обнаружено, то возвращается последний элемент, как в примерах с переменными number1 и text2.

В случае с операцией or поиску подлежит первое истинное значение. При его обнаружении вычисление прекращается, а само истинное значение возвращается, как в примерах с переменными number и text. Если же такое значение не найдено, то возвращается последний элемент, как в ситуации с переменной what

2. Выражение присваивания 

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

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

>>> numbers = [1, 2, 3, 4]
>>> eval(str(numbers))
[1, 2, 3, 4]
>>> eval("numbers = [1, 2, 3, 4]")
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<string>", line 1
    numbers = [1, 2, 3, 4]
            ^
SyntaxError: invalid syntax

В Pyhton 3.8 были добавлены выражения присваивания, которые позволяют наделить особый вид инструкции присваивания характеристиками выражений. По сути, мы можем присвоить объект переменной (компонент присваивания), и в то же время она будет вычислена в значение (компонент выражения). Данная функциональность предполагает применение нового, так называемого “моржового оператора” —  :=. Приведем пример: 

>>> (numbers1 := [1, 2, 3])
[1, 2, 3]
>>> eval("(numbers2 := [2, 3, 4])")
[2, 3, 4]

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

Допустим, у нас есть список чисел, и нам необходимо вычислить нарастающую сумму, которая сохраняется в объекте списка. Воспользуемся функцией accumulate в модуле itertools, как показано в примере: 

>>> # Список чисел для вычисления суммы 
>>> numbers = [1, 2, 3, 4]
>>> 
>>> # Вычисление накопительной суммы 
>>> from itertools import accumulate
>>> list(accumulate(numbers))
[1, 3, 6, 10]

Есть еще одно решение с применением выражения присваивания, которое представлено ниже:

>>> total = 0
>>> [total := total + x for x in numbers]
[1, 3, 6, 10]

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

3. Управление контекстом: with 

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

with open("some_file.txt") as file:
    text_data = file.read()

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

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

# 1. Открываем файл 
file = open("some_file.txt")

# 2. Выполняем операции с файлом 
text_data = file.read()

# 3. Закрываем файл 
file.close()

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

Назначение инструкции with состоит в выполнении этой стандартной процедуры за нас. Точнее говоря, файл автоматически закрывается после выхода из инструкции with. Обратимся к примеру: 

>>> file0 = open("file0.txt", "w")
>>> file0.write("some random data")
16
>>> print("Is the file0 closed?", file0.closed)
Is the file0 closed? False
>>> with open("file1.txt", "w") as file1:
...   file1.write("some random data")
... 
>>> print("Is the file1 closed?", file1.closed)
Is the file1 closed? True

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

Заключение 

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

1.При наличии составных условных инструкций Python выполняет сокращенные вычисления. В случае с операцией and возвращается первое ложное значение или последний элемент. В случае с операцией or возвращается первое истинное значение или последний элемент. 

2. Выражения и инструкции отличаются друг от друга. Инструкция присваивания не производит значение, тогда как выражение присваивания присваивает переменную и одновременно с этим вычисляет значение. 

3. Инструкция with применяется при необходимости управления определенным контекстом и чаще всего востребована при работе с файлами. Контекстный менеджер автоматически закрывает файл в момент выхода из контекста. 

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Yong Cui: 3 Seemingly Simple Python Features That Confuse Beginners

Предыдущая статьяReact Query - залог эффективных запросов
Следующая статьяКак удалить одинаковые данные из отсортированного массива