Оператор присваивания в Python: Пишите надежные присваивания
Оглавление
- операторы присваивания и оператор присваивания
- Назначение Утверждения в действии
- расширенные операторы присваивания в Python
- Другие Варианты Присвоения
- неявные назначения в Python
- незаконные и опасные задания в Python
- заключение
Операторы присваивания в Python позволяют вам определять операторы присваивания. Операторы этого типа позволяют создавать, инициализировать и обновлять переменные в вашем коде. Переменные являются фундаментальным элементом каждого фрагмента кода, а операторы присваивания дают вам полный контроль над созданием и изменением переменных.
Ознакомившись с оператором присваивания Python и его использованием для написания инструкций присваивания, вы получите мощные инструменты для написания более качественного и надежного кода на Python.
В этом руководстве вы узнаете:
- Используйте оператор присваивания в Python для написания инструкций присваивания
- Воспользуйтесь преимуществами расширенных назначений в Python
- Изучите варианты присвоения, такие как выражения присвоения и управляемые атрибуты
- Узнайте о незаконных и опасных назначениях в Python
Вы глубоко погрузитесь в инструкции присваивания Python. Чтобы извлечь максимальную пользу из этого руководства, вы должны освоиться с несколькими основными темами, включая переменные, встроенные типы данных, общие сведения, функции и ключевые слова Python . Прежде чем перейти к некоторым из последующих разделов, вы также должны ознакомиться с промежуточными темами, такими как объектно-ориентированное программирование, константы, импорт, подсказки по типу, свойства, дескрипторы, и декораторы.
Бесплатный исходный код: Нажмите здесь, чтобы скачать бесплатный исходный код оператора присваивания, который вы будете использовать для написания инструкций присваивания, позволяющих вам создавать, инициализировать и обновлять переменные в вашем коде.
Операторы присваивания и оператор присваивания
Одной из самых мощных функций языка программирования является возможность создавать переменные , получать к ним доступ и изменять их. В Python переменная - это имя, которое ссылается на конкретное значение или объект, позволяя вам повторно использовать это значение или объект в вашем коде.
Синтаксис оператора присваивания
Чтобы создать новую переменную или обновить значение существующей переменной в Python, вы будете использовать оператор присваивания. Этот оператор состоит из следующих трех компонентов:
- Левый операнд, который должен быть переменной
- Оператор присваивания (
=) - Правый операнд, который может быть конкретным значением, объектом или выражением
Вот как обычно выглядит оператор присваивания в Python:
variable = expressionпредварительно> кодовый блок>Здесь
variableпредставляет собой общую переменную Python, в то время какexpressionпредставляет любой объект Python, который вы можете предоставить в виде конкретного значения, также известного как литерал —или выражение, вычисляющее значение.Чтобы выполнить оператор присваивания, подобный описанному выше, Python выполняет следующие действия:
- Вычислите правое выражение, чтобы получить конкретное значение или объект. Это значение будет храниться по определенному адресу памяти вашего компьютера.
- Сохраните адрес памяти объекта в левой переменной. На этом шаге создается новая переменная, если текущая еще не существует, или обновляется значение существующей переменной.
На втором шаге показано, что переменные в Python работают иначе, чем в других языках программирования. В Python переменные не являются контейнерами для объектов. Переменные Python указывают на значение или объект через его адрес в памяти. Они хранят адреса памяти, а не объекты.
Это различие в поведении напрямую влияет на то, как данные перемещаются в Python, который всегда по ссылке. В большинстве случаев эта разница не имеет значения для вашего повседневного программирования, но все равно полезно знать об этом.
Оператор присваивания
Центральным компонентом оператора присваивания является оператор присваивания. Этот оператор представлен символом
=, который разделяет два операнда:
- Переменная
- Значение или выражение, результатом вычисления которого является конкретное значение
Операторы - это специальные символы, которые выполняют математические,, логические и побитовые операции в языке программирования. Объекты (или object), над которыми работает оператор, называются операндами.
Унарные операторы, такие как
notЛогический оператор, работают с одним объектом или операндом, в то время как двоичные операторы работают с двумя. Это означает, что оператор присваивания является двоичным оператором.Примечание: Как и C, Python использует
==для сравнения на равенство и=для присваиваний. В отличие от C, Python не позволяет вам случайно использовать оператор присваивания (=) при сравнении на равенство.Равенство - это симметричное отношение, а присваивание - нет. Например, выражение
a == 42эквивалентно42 == a. В отличие от этого, утверждениеa = 42является правильным и законным, в то время как42 = aнедопустимо. Вы узнаете больше о незаконных назначениях позже.Правым операндом в инструкции присваивания может быть любой объект Python, такой как число, список, строка, словарь или даже объект, определенный пользователем. Это также может быть выражение. В конце концов, выражения всегда вычисляют конкретные объекты, которые и являются их возвращаемым значением.
Вот несколько примеров присваиваний в Python:
>>> number = 42 >>> greeting = "Hello, World!" >>> total = 15 + 25 >>> is_true = 42 < 84предварительно> кодовый блок>В первых двух примерах присваивания в этом фрагменте кода используются конкретные значения, также известные как литералы, для создания и инициализации
numberиgreeting. В третьем примере результат математического выражения присваивается переменнойtotal, в то время как в последнем примере используется логическое выражение .Примечание: Вы можете использовать встроенную функцию
id()для проверки адреса памяти, сохраненного в заданной переменной .Вот краткий пример того, как работает эта функция:
>>> number = 42 >>> id(number) 4311827984предварительно> кодовый блок>Число в выходных данных представляет собой адрес памяти, сохраненный в
number. По этому адресу Python может получить доступ к содержимомуnumber, которое в данном примере является целым числом42.Если вы запустите этот код на своем компьютере, то получите другой адрес памяти, поскольку это значение варьируется от выполнения к выполнению и от компьютера к компьютеру.
В отличие от выражений, операторы присваивания не имеют возвращаемого значения, поскольку их целью является установление связи между переменной и ее значением. Вот почему интерпретатор Python не выдает никаких выходных данных в приведенных выше примерах.
Теперь, когда вы знаете основы как написать инструкцию присваивания, пришло время разобраться с почему вы хотели бы использовать one.
Назначения и переменные
Оператор присваивания - это явный способ связать имя с объектом в Python. Вы можете использовать этот оператор для двух основных целей:
- Создание и инициализация новых переменных
- Обновление значений существующих переменных
Когда вы впервые используете имя переменной в качестве левого операнда в операторе присваивания, вы создаете новую переменную. В то же время вы инициализируете переменную, чтобы она указывала на значение правильного операнда.
С другой стороны, когда вы используете существующую переменную в новом присвоении, вы обновляете или изменяете значение переменной. Строго говоря, при каждом новом присвоении переменная будет ссылаться на новое значение и перестанет ссылаться на старое. Python выполнит сборку мусора всех значений, на которые больше не ссылается ни одна существующая переменная.
Операторы присваиванияне только присваивают значение переменной, но и определяют тип данных для данной переменной. Это дополнительное поведение является еще одной важной деталью, которую следует учитывать в такого рода заявлениях.
Поскольку Python является языком с динамической типизацией, последовательные присвоения данной переменной могут изменять тип данных переменной. Изменение типа данных переменной во время выполнения программы считается плохой практикой и настоятельно не рекомендуется. Это может привести к появлению незначительных ошибок, которые бывает трудно отследить.
В отличие от математических уравнений, в присваиваниях Python левый операнд должен быть переменной, а не выражением или значением. Например, следующая конструкция недопустима, и Python помечает ее как недопустимый синтаксис:
>>> a = 3 >>> b = 4 >>> hypotenuse ** 2 = a ** 2 + b ** 2 ... SyntaxError: cannot assign to expression here. Maybe you meant '==' instead of '='?предварительно> кодовый блок>В этом примере выражения расположены по обе стороны от знака
=, а это запрещено в коде Python. В сообщении об ошибке предполагается, что вы, возможно, путаете оператор равенства с оператором присваивания, но это не так. Вы действительно выполняете недопустимое задание.Чтобы исправить эту конструкцию и преобразовать ее в допустимое назначение, вам нужно будет сделать что-то вроде следующего:
>>> from math import sqrt >>> a = 3 >>> b = 4 >>> hypotenuse = sqrt(a ** 2 + b ** 2) >>> hypotenuse 5.0предварительно> кодовый блок>В этом фрагменте кода вы сначала импортируете функцию
sqrt()из модуляmath. Затем вы изолируете переменнуюhypotenuseв исходном уравнении с помощью функцииsqrt(). Теперь ваш код работает корректно.Теперь вы знаете, какой синтаксис является недопустимым. Но не думайте, что операторы присваивания являются жесткими и негибкими. На самом деле, как вы узнаете далее, они предоставляют множество возможностей для настройки.
Другой синтаксис присваивания
Операторы присваивания в Python довольно гибкие и универсальные. Вы можете написать их несколькими способами, в зависимости от ваших конкретных потребностей и предпочтений. Вот краткий обзор основных способов написания присваиваний в Python:
# Base assignments variable = value # A literal, such as None, 0, 3.14, "Hello", {} variable = expression # Math, Boolean, bitwise expression, function calls... # Multiple assignments variable_1 = variable_2 = ... = variable_n = expression # Parallel assignments variable_1, variable_2, ..., variable_n = value_1, value_2, ..., value_n variable_1, variable_2, ..., variable_n = exp_1, exp_2, ..., exp_n # Augmented assignments existing_variable += value existing_variable += expression # Parallel assignments with iterable unpacking variable_1, variable_2, ..., variable_n = n_length_iterable (variable_1, variable_2, ..., variable_n) = n_length_iterable [variable_1, variable_2, ..., variable_n] = n_length_iterable variable, *bag_variable, ..., variable_n = unknown_length_iterableпредварительно> кодовый блок>До этого момента вы в основном изучали синтаксис базового назначения из приведенного выше фрагмента кода. В следующих разделах вы узнаете о множественных, параллельных и расширенных назначениях. Вы также узнаете о назначениях с итеративной распаковкой.
Читайте дальше, чтобы увидеть инструкции присваивания в действии!
Операторы присваивания в действии
Вы найдете и будете использовать операторы присваивания повсюду в вашем коде на Python. Они являются фундаментальной частью языка, предоставляя явный способ создания, инициализации и изменения переменных.
Вы можете использовать операторы присваивания с простыми именами, например
numberилиcounter. Вы также можете использовать присваивания в более сложных сценариях, например, с помощью:
- Полные имена атрибутов, например
user.name- Индексы и фрагментов изменяемых последовательностей, таких как
a_list[i]иa_list[i:j]- Словарь ключи, например
a_dict[key]Этот список не является исчерпывающим. Однако он дает вам некоторое представление о том, насколько гибкими являются эти утверждения. Вы даже можете присвоить несколько значений равному числу переменных в одной строке, что обычно называется параллельным присвоением. Кроме того, вы можете одновременно присваивать значения в iterable группе переменных, разделенных запятыми, в ходе так называемой операции итеративной распаковки.
В следующих разделах вы глубже познакомитесь со всеми этими темами и несколькими другими интересными вещами, которые вы можете делать с помощью операторов присваивания в Python.
Инициализация и обновление переменных
Наиболее простым вариантом использования оператора присваивания является создание новой переменной и ее инициализация с использованием определенного значения или выражения:
>>> counter = 0 >>> celsius = 25 >>> fahrenheit = (celsius * 9 / 5) + 32 >>> user_template = {"id": None, "name": "", "permissions": ("r",)} >>> welcome_message = "Welcome to Real Python!" >>> is_empty = Falseпредварительно> кодовый блок>Все эти инструкции создают новые переменные, присваивая им начальные значения или выражения. В качестве начального значения всегда следует использовать наиболее разумное и наименее неожиданное значение, которое вы можете придумать. Например, инициализация счетчика значением, отличным от
0, может привести к путанице и неожиданностям, поскольку счетчики почти всегда начинают с того, что не подсчитывают никаких объектов.Обновление текущего значения переменной или состояния - это еще один распространенный вариант использования операторов присваивания. В Python присвоение нового значения существующей переменной не изменяет текущее значение переменной. Вместо этого это приводит к тому, что переменная ссылается на другое значение. Предыдущее значение будет удалено, если на него не ссылается никакая другая переменная.
Рассмотрим следующие примеры:
>>> greeting = "Hello, World!" >>> greeting 'Hello, World!' >>> greeting = "Hi, Pythonistas!" >>> greeting 'Hi, Pythonistas!'предварительно> кодовый блок>В этих примерах выполняются два последовательных присвоения одной и той же переменной. В первом примере строка
"Hello, World!"присваивается новой переменной с именемgreeting.Второе присваивание обновляет значение
greeting, переназначая ему строку"Hi, Pythonistas!". В этом примере исходное значениеgreeting— строка"Hello, World!"— потеряно и удалено в корзину. С этого момента вы не сможете получить доступ к старой строке"Hello, World!".Несмотря на то, что выполнение нескольких назначений для одной и той же переменной во время выполнения программы является обычной практикой, вам следует использовать эту функцию с осторожностью. Изменение значения переменной может затруднить чтение, понимание и отладку вашего кода. Чтобы полностью понять код, вам нужно запомнить все места, где переменная была изменена, и последовательный порядок этих изменений.
Поскольку назначения также определяют тип данных для своих целевых переменных, ваш код также может случайно изменить тип данной переменной во время выполнения. Подобное изменение может привести к возникновению ошибок, таких как
AttributeErrorисключения. Помните, что у строк нет таких методов и атрибутов, как, например, у списков или словарей.Создание нескольких переменных, ссылающихся на один и тот же объект
В Python вы можете заставить несколько переменных ссылаться на один и тот же объект в строке множественного назначения. Это может быть полезно, когда вы хотите инициализировать несколько похожих переменных, используя одно и то же начальное значение:
>>> letter_counter = word_counter = 0 >>> id(letter_counter) == id(word_counter) Trueпредварительно> кодовый блок>В этом примере вы объединяете два оператора присваивания в одну строку. Таким образом, две ваши переменные ссылаются на одно и то же начальное значение
0. Обратите внимание, что обе переменные содержат один и тот же адрес памяти, поэтому они указывают на один и тот же экземпляр0.Когда дело доходит до целочисленных переменных, Python демонстрирует любопытное поведение. Он предоставляет числовой интервал, в котором множественные присваивания ведут себя так же, как независимые присваивания. Рассмотрим следующие примеры:
>>> # Independent assignments >>> n = 42 >>> m = 42 >>> id(n) == id(m) True >>> # Multiple assignments >>> x = y = 42 >>> id(x) == id(y) Trueпредварительно> кодовый блок>Для создания
nиmиспользуются независимые присвоения. Следовательно, они должны указывать на разные экземпляры числа42. Однако обе переменные содержат один и тот же объект, что вы подтверждаете, сравнивая их соответствующие адреса в памяти.Теперь проверьте, что происходит, когда вы используете большее начальное значение:
>>> n = 300 >>> m = 300 >>> id(x) == id(y) False >>> x = y = 300 >>> id(x) == id(y) Trueпредварительно> кодовый блок>Теперь
nиmсодержат разные адреса памяти, что означает, что они указывают на разные экземпляры целого числа300. В отличие от этого, когда вы используете несколько назначений, обе переменные ссылаются на один и тот же объект. Это небольшое различие может сэкономить вам немного памяти, если вы часто инициализируете целочисленные переменные в своем коде.Неявное выполнение независимых присваиваний, указывающих на одно и то же целое число, на самом деле является оптимизацией, называемой интернированием. Он состоит из глобального кэширования наиболее часто используемых целочисленных значений в повседневном программировании.
По сути, Python определяет числовой интервал, в течение которого происходит стажировка. Это интервал стажировки для целых чисел. Вы можете определить этот интервал с помощью небольшого скрипта, подобного следующему:
# interning.py from platform import python_version interning = [ x for x, y in zip(range(-10, 500), range(-10, 500)) if x is y ] print( f"Interning interval for Python {python_version()} is:" f" [{interning[0]} to {interning[-1]}]" )предварительно> кодовый блок>Этот скрипт поможет вам определить интервал стажировки, сравнивая целые числа от
-10до500. Если вы запустите скрипт из командной строки, то получите результат, похожий на следующий:$ python interning.py Interning interval for Python 3.11.0 is: (-5 to 256)предварительно> кодовый блок>Этот вывод означает, что если вы используете одно число между
-5и256для инициализации нескольких переменных в независимых инструкциях, то все эти переменные будут указывать на один и тот же объект, что поможет вам сэкономить небольшие биты данных. память в вашем коде.В отличие от этого, если вы используете число, которое выходит за пределы интервала интернирования, ваши переменные будут указывать на разные объекты. Каждый из этих объектов будет занимать отдельную область памяти.
Обновление списков с помощью индексов и срезов
Вы можете использовать оператор присваивания для изменения значения, хранящегося с заданным индексом в списке Python. Этот оператор также работает со списком фрагментов. Синтаксис для написания этих типов операторов присваивания следующий:
a_list[index] = expression a_list[start:stop:step] = expressionпредварительно> кодовый блок>В первой конструкции
expressionможет возвращать любой объект Python, включая другой список. Во второй конструкцииexpressionдолжен возвращать последовательность значений в виде списка, кортежа или любой другой последовательности. Вы получитеTypeError, еслиexpressionвозвращает одно значение.Примечание: При создании объектов
sliceможно использовать до трех аргументов. Этими аргументами являютсяstart,stop, иstep. Они определяют число, с которого начинается срез, число, на котором срез должен прекращаться для получения значений, и шаг между значениями.Вот пример обновления отдельного значения в списке:
>>> numbers = [1, 2, 7, 4, 5] >>> numbers [1, 2, 7, 4, 5] >>> numbers[2] = 3 >>> numbers [1, 2, 3, 4, 5]предварительно> кодовый блок>В этом примере вы обновляете значение по индексу
2, используя инструкцию присваивания. Исходный номер с этим индексом был7, а после присвоения этот номер будет равен3.Примечание: Использование индексов и оператора присваивания для обновления значения в кортеже или символа в строке невозможно, поскольку кортежи и строки являются неизменяемыми типами данных в Python.
Их неизменность означает, что вы не можете изменить их элементы на месте:
>>> numbers = (1, 2, 2, 4, 5) >>> numbers[2] = 3 Traceback (most recent call last): ... TypeError: 'tuple' object does not support item assignment >>> letters = "ABcDE" >>> letters[2] = "C" Traceback (most recent call last): ... TypeError: 'str' object does not support item assignmentпредварительно> кодовый блок>Вы не можете использовать оператор присваивания для изменения отдельных элементов в кортежах или строках. Эти типы данных являются неизменяемыми и не поддерживают присвоение элементов.
Важно отметить, что вы не можете добавлять новые значения в список, используя индексы, которых нет в целевом списке:
>>> numbers[5] = 6 Traceback (most recent call last): ... IndexError: list assignment index out of rangeпредварительно> кодовый блок>В этом примере вы пытаетесь добавить новое значение в конец
numbers, используя несуществующий индекс. Это присвоение недопустимо, поскольку нет способа гарантировать, что новые индексы будут последовательными. Если вы когда-нибудь захотите добавить одно значение в конец списка, используйте метод.append().Если вы хотите обновить несколько последовательных значений в списке, то вы можете использовать разбиение на части и оператор присваивания:
>>> letters = ["A", "b", "c", "D"] >>> letters[1:3] = ["B", "C"] >>> letters ['A', 'B', 'C', 'D'] >>> letters[3:] = ("F", "G") >>> letters ['A', 'B', 'C', 'F', 'G'] >>> letters[3:3] = ["D"] >>> letters ['A', 'B', 'C', 'D', 'F', 'G'] >>> letters[1::2] = ["b", "d", "g"] >>> letters ['A', 'b', 'C', 'd', 'F', 'g']предварительно> кодовый блок>В первом примере вы обновляете буквы между индексами
1и3, не включая букву в3. Во втором примере буквы из индекса3обновляются до конца списка. Обратите внимание, что при таком разбиении на фрагменты к списку добавляется новое значение, поскольку целевой фрагмент короче назначенных значений.Также обратите внимание, что новые значения были предоставлены через кортеж, что означает, что этот тип присваивания позволяет вам использовать другие типы последовательностей для обновления вашего целевого списка.
В третьем примере обновляется одно значение, используя фрагмент, в котором оба индекса равны. В этом примере назначение вставляет новый элемент в целевой список.
В последнем примере вы используете
stepиз2, чтобы заменить чередующиеся буквы их строчными аналогами. Эта нарезка начинается с индекса1и выполняется по всему списку, каждый раз переходя на два элемента.Добавление и обновление ключей словаря
Обновление значения существующего ключа или добавление новых пар ключ-значение в словарь - еще один распространенный вариант использования операторов присваивания. Для выполнения этих операций вы можете использовать следующий синтаксис:
a_dict[existing_key] = expression a_dict[new_key] = expressionпредварительно> кодовый блок>Первая конструкция помогает вам обновить текущее значение существующего ключа, в то время как вторая конструкция позволяет вам добавить новую пару ключ-значение в словарь.
Например, чтобы обновить существующий ключ, вы можете сделать что-то вроде этого:
>>> inventory = {"apple": 100, "orange": 80, "banana": 120} >>> inventory {'apple': 100, 'orange': 80, 'banana': 120} >>> inventory["orange"] = 140 >>> inventory {'apple': 100, 'orange': 140, 'banana': 120}предварительно> кодовый блок>В этом примере вы обновляете текущий запас апельсинов в вашем магазине, используя присвоение. Левый операнд - это существующий ключ словаря, а правый операнд - это желаемое новое значение.
Хотя вы не можете добавлять новые значения в список путем присваивания, словари позволяют добавлять новые пары ключ-значение с помощью оператора присваивания. В приведенном ниже примере вы добавляете ключ
lemonвinventory:>>> inventory["lemon"] = 100 >>> inventory {'apple': 100, 'orange': 140, 'banana': 120, 'lemon': 100}предварительно> кодовый блок>В этом примере вы успешно добавили новую пару ключ-значение в свой инвентарь с помощью
100единиц измерения. Это добавление возможно потому, что словари содержат не последовательные индексы, а уникальные ключи, которые можно безопасно добавлять путем присвоения.Выполнение параллельных заданий
Оператор присваивания выполняет нечто большее, чем просто присваивает результат одного выражения одной переменной. Он также может прекрасно справляться с одновременным присвоением нескольких значений нескольким переменным в процессе, известном как параллельное присвоение .
Вот общий синтаксис для параллельных назначений в Python:
variable_1, variable_2, ..., variable_n = value_1, value_2, ..., value_n variable_1, variable_2, ..., variable_n = exp_1, exp_2, ..., exp_n (variable_1, variable_2, ..., variable_n) = exp_1, exp_2, ..., exp_n [variable_1, variable_2, ..., variable_n] = exp_1, exp_2, ..., exp_nпредварительно> кодовый блок>Обратите внимание, что левая часть инструкции может быть либо кортежем, либо списком переменных. Помните, что для создания кортежа вам просто нужен ряд элементов, разделенных запятыми. В данном случае эти элементы должны быть переменными.
Правая часть инструкции должна быть последовательностью значений или выражений, которые можно повторять. В любом случае количество элементов в правом операнде должно соответствовать количеству переменных в левом. В противном случае вы получите
ValueErrorисключение.В следующем примере вы вычисляете два решения квадратного уравнения, используя параллельное задание:
>>> from math import sqrt >>> a, b, c = 2.0, -1.0, -4.0 >>> x1, x2 = ( ... (-b - sqrt(b**2 - 4 * a * c)) / (2 * a), ... (-b + sqrt(b**2 - 4 * a * c)) / (2 * a), ... ) >>> f"{x1=}, {x2=}" 'x1=-1.1861406616345072, x2=1.6861406616345072'предварительно> кодовый блок>В этом примере вы сначала импортируете
sqrt()из модуляmath. Затем вы инициализируете коэффициенты уравнения в параллельном задании.Решение уравнения вычисляется в другом параллельном задании. Левый операнд содержит набор из двух переменных,
x1иx2. Правый операнд состоит из набора выражений, которые вычисляют решения уравнения. Обратите внимание, что каждый результат присваивается каждой переменной по позиции.Классическим вариантом использования параллельного присваивания является замена значений между переменными:
>>> previous_value = 42 >>> next_value = 43 >>> next_value, previous_value = previous_value, next_value >>> previous_value 43 >>> next_value 42предварительно> кодовый блок>Выделенная строка совершает волшебство и меняет местами значения
previous_valueиnext_valueодновременно. Обратите внимание, что в языке программирования, который не поддерживает такого рода присвоения, вам пришлось бы использовать временную переменную для получения того же эффекта:>>> previous_value = 42 >>> next_value = 43 >>> temp = previous_value >>> previous_value = next_value >>> next_value = temp >>> previous_value 43 >>> next_value 42предварительно> кодовый блок>В этом примере вместо использования параллельного присваивания для обмена значениями между переменными вы используете новую переменную для временного хранения значения
previous_value, чтобы избежать потери ссылки на него.В качестве конкретного примера того, когда вам нужно поменять местами значения между переменными, предположим, вы изучаете, как реализовать алгоритм пузырьковой сортировки , и у вас появилась следующая функция:
>>> def bubble_sort_list(a_list): ... n = len(a_list) ... for i in range(n): ... is_sorted = True ... for j in range(n - i - 1): ... if a_list[j] > a_list[j + 1]: ... a_list[j], a_list[j + 1] = a_list[j + 1], a_list[j] ... is_sorted = False ... if is_sorted: ... break ... return a_list ... >>> bubble_sort_list([1, 3, 2, 4, 7, 6, 3, 8, 9, 1]) [1, 1, 2, 3, 3, 4, 6, 7, 8, 9]предварительно> кодовый блок>В выделенной строке вы используете параллельное присвоение, чтобы поменять местами значения, если текущее значение меньше следующего значения в списке ввода. Чтобы глубже изучить алгоритм пузырьковой сортировки и алгоритмы сортировки в целом, ознакомьтесь с Алгоритмами сортировки в Python.
Распаковка повторяющихся объектов
Вы можете использовать операторы присваивания для итеративной распаковки в Python. Распаковка итеративной переменной означает присвоение ее значений ряду переменных, одной за другой. Повторяемая функция должна быть правым операндом в присваивании, в то время как переменные должны быть левым операндом.
Как и при параллельном присвоении, переменные должны быть представлены в виде кортежа или списка. Количество переменных должно соответствовать количеству значений в итерационной таблице. В качестве альтернативы вы можете использовать оператор распаковки (
*), чтобы получить несколько значений в переменной, если количество переменных не соответствует повторяемой длине.Вот общий синтаксис для итеративной распаковки в Python:
variable_1, variable_2, ..., variable_n = n_length_iterable (variable_1, variable_2, ..., variable_n) = n_length_iterable [variable_1, variable_2, ..., variable_n] = n_length_iterable variable, *bag_variable, ..., variable_n = unknown_length_iterableпредварительно> кодовый блок>Итеративная распаковка - это мощная функция, которую вы можете использовать во всем своем коде. Она может помочь вам написать более читаемый и краткий код. Например, вы можете обнаружить, что делаете что-то вроде этого:
>>> numbers = [1, 2, 3, 4] >>> one = numbers[0] >>> two = numbers[1] >>> three = numbers[2] >>> four = numbers[3] >>> one 1 >>> two 2 >>> three 3 >>> four 4предварительно> кодовый блок>Всякий раз, когда вы делаете что-то подобное в своем коде, заменяйте это на более удобочитаемую итеративную распаковку, используя единственное и элегантное назначение, как в следующем фрагменте кода:
>>> numbers = [1, 2, 3, 4] >>> one, two, three, four = numbers >>> one 1 >>> two 2 >>> three 3 >>> four 4предварительно> кодовый блок>Список
numbersв правой части содержит четыре значения. Оператор присваивания преобразует эти значения в четыре переменные в левой части инструкции. Значения вnumbersприсваиваются переменным в том же порядке, в котором они отображаются в итерационной таблице. Присваивание выполняется по позиции.Примечание: Поскольку наборы в Python также являются повторяемыми, вы можете использовать их в итерационной операции распаковки. Однако будет неясно, какое значение относится к какой переменной, поскольку наборы представляют собой неупорядоченные структуры данных.
В приведенном выше примере показана наиболее распространенная форма итерационной распаковки в Python. Главное условие для работы примера заключается в том, чтобы количество переменных соответствовало количеству значений в итерационной таблице.
Что делать, если вы заранее не знаете повторяемую длину? Сработает ли распаковка? Это сработает, если вы используете оператор
*для упаковки нескольких значений в одну из ваших целевых переменных.Например, предположим, что вы хотите разложить первое и второе значения в
numbersна две разные переменные. Кроме того, вы хотели бы упаковать остальные значения в одну переменную, которая удобно называетсяrest. В этом случае вы можете использовать оператор распаковки, как в следующем коде:>>> first, second, *rest = numbers >>> first 1 >>> second 2 >>> rest [3, 4]предварительно> кодовый блок>В этом примере
firstиsecondсодержат первое и второе значения вnumbersсоответственно. Эти значения присваиваются по позиции. Оператор*преобразует все оставшиеся значения во входной итерации вrest.Оператор распаковки (
*) может находиться в любой позиции в вашей последовательности целевых переменных. Однако вы можете использовать только один экземпляр оператора:>>> *head, last = numbers >>> head [1, 2, 3] >>> last 4 >>> head, *body, tail = numbers >>> head 1 >>> body [2, 3] >>> tail 4 >>> *head, *rest = numbers ... SyntaxError: multiple starred expressions in assignmentпредварительно> кодовый блок>Повторяющийся оператор распаковки работает в любой позиции вашего списка переменных. Обратите внимание, что для каждого задания можно использовать только один оператор распаковки. Использование более чем одного оператора распаковки запрещено и приводит к возникновению проблемы.
SyntaxError.Удаление ненужных значений из iterable - это обычный вариант использования оператора распаковки iterable. Рассмотрим следующий пример:
>>> *_, useful = numbers >>> useful 4 >>> _ [1, 2, 3]предварительно> кодовый блок>В Python, если вы хотите указать, что переменная использоваться не будет, то в качестве имени переменной используется знак подчеркивания (
_). В этом примереusefulсодержит единственное значение, которое вам нужно использовать из входной итеративной переменной. Переменная_является заполнителем, который гарантирует, что распаковка будет работать корректно. Вы не будете использовать значения, которые попадают в эту одноразовую переменную.Примечание: В приведенном выше примере, если вашей целевой итерацией является тип данных последовательности, такой как список или кортеж, то лучше всего напрямую обращаться к ее последнему элементу.
Для этого вы можете использовать индекс
-1:>>> useful = numbers[-1] >>> useful 4предварительно> кодовый блок>Использование
-1дает вам доступ к последнему элементу любого типа данных последовательности. В отличие от этого, если вы имеете дело с итераторами, то вы не сможете использовать индексы. Вот тогда вам на помощь приходит синтаксис*_.Шаблон, использованный в приведенном выше примере, удобен, когда у вас есть функция, возвращающая несколько значений, и вам нужно включить в свой код только несколько из этих значений. Хорошим примером такой ситуации может служить функция
os.walk().Эта функция позволяет вам рекурсивно перебирать содержимое каталога. Функция возвращает объект generator, который выдает кортежи из трех элементов. Каждый кортеж содержит следующие элементы:
- Путь к текущему каталогу в виде строки
- Имена всех ближайших подкаталогов в виде списка строк
- Имена всех файлов в текущем каталоге в виде списка строк
Теперь скажите, что вы хотите просмотреть свой домашний каталог и перечислить только файлы. Вы можете сделать что-то вроде этого:
>>> import os >>> for content in os.walk("/path/to/your/home"): ... *_, filenames = content ... print(filenames) ...предварительно> кодовый блок>Этот код выдаст длинный вывод в зависимости от текущего содержимого вашего домашнего каталога. Обратите внимание, что для работы примера вам необходимо указать строку с путем к вашей пользовательской папке. Переменная-заполнитель
_будет содержать ненужные данные.В отличие от этого, переменная
filenamesбудет содержать список файлов в текущем каталоге, то есть те данные, которые вам нужны. Код выведет список имен файлов. Попробуйте!Предоставление значений аргументов по умолчанию
Оператор присваивания также полезен, когда вам нужно указать значения аргументов по умолчанию в ваших функциях и методах. Значения аргументов по умолчанию позволяют определить функции, которые принимают аргументы с разумными значениями по умолчанию. Эти значения по умолчанию позволяют вам вызывать функцию с определенными значениями или просто полагаться на значения по умолчанию.
В качестве примера рассмотрим следующую функцию:
>>> def greet(name="World"): ... print(f"Hello, {name}!") ...предварительно> кодовый блок>Эта функция принимает один аргумент, называемый
name. Этот аргумент имеет разумное значение по умолчанию, которое будет использоваться при вызове функции без аргументов. Чтобы предоставить это разумное значение по умолчанию, вы используете присваивание.примечание: по ОПТОСОЗ 8, руководства по стилю для кода Python, вы не должны использовать пробелы вокруг оператора присваивания при предоставлении умолчанию значения аргументов в функции определения.
Вот как работает эта функция:
>>> greet() Hello, World! >>> greet("Pythonista") Hello, Pythonista!предварительно> кодовый блок>Если вы не укажете имя во время вызова
greet(), то функция использует значение по умолчанию, указанное в определении. Если вы укажете имя, то функция будет использовать его вместо имени по умолчанию.На данный момент вы многое узнали об операторе присваивания в Python и о том, как его использовать для написания различных типов инструкций присваивания. В следующих разделах вы познакомитесь с замечательной функцией операторов присваивания в Python. Вы узнаете о дополненных заданиях.
Расширенные операторы присваивания в Python
Python поддерживает так называемые расширенные присваивания. Расширенное присваивание объединяет оператор присваивания с другим оператором, чтобы сделать инструкцию более краткой. Большинство математических и побитовых операторов Python имеют расширенный вариант присваивания, который выглядит примерно так:
variable $= expressionпредварительно> кодовый блок>Обратите внимание, что
$не является допустимым оператором Python. В данном примере это заполнитель для универсального оператора. Этот оператор работает следующим образом:
- Вычислите
expression, чтобы получить значение.- Выполните операцию, определенную оператором, который имеет префикс
=, используя предыдущее значениеvariableи возвращаемое значениеexpressionв качестве операндов.- Присвоить результирующее значение обратно
variable.На практике расширенное задание, подобное приведенному выше, эквивалентно следующему утверждению:
variable = variable $ expressionпредварительно> кодовый блок>Как вы можете заключить, расширенные задания - это синтаксический сахар. Они предоставляют сокращенную запись для определенного и популярного вида заданий.
Например, предположим, что вам нужно определить переменную
counterдля подсчета некоторых данных в вашем коде. Вы можете использовать оператор+=для увеличенияcounterна1, используя следующий код:>>> counter = 0 >>> counter += 1 >>> counter 1 >>> counter += 1 >>> counter 2предварительно> кодовый блок>В этом примере оператор
+=, известный как дополненное сложение, добавляет1к предыдущему значению вcounterкаждый раз, когда вы запускаете инструкциюcounter += 1.Важно отметить, что в отличие от обычных назначений, расширенные задания не создают новых переменных. Они позволяют вам только обновлять существующие переменные. Если вы используете расширенное присваивание с неопределенной переменной, то вы получаете
NameError:>>> x += 1 Traceback (most recent call last): ... NameError: name 'x' is not definedпредварительно> кодовый блок>Python вычисляет правую часть инструкции, прежде чем присвоить результирующее значение обратно целевой переменной. В этом конкретном примере, когда Python пытается вычислить
x + 1, он обнаруживает, чтоxне определен.Отлично! Теперь вы знаете, что расширенное присваивание заключается в объединении оператора присваивания с другим оператором, например математическим или побитовым. Чтобы продолжить обсуждение, вы узнаете, какие математические операторы имеют расширенные варианты в Python.
Расширенные математические операторы присваивания
Уравнение типа x = x + b не имеет смысла в математике. Но в программировании утверждение типа
x = x + bабсолютно корректно и может быть чрезвычайно полезным. Он добавляетbкxи переназначает результат обратно наx.Как вы уже узнали, в Python есть оператор для сокращения
x = x + b. Да, оператор+=позволяет вместо этого написатьx += b. Python также предлагает расширенные операторы присваивания для большинства математических операций. Вот краткое описание:
Operator Description Example Equivalent +=Adds the right operand to the left operand and stores the result in the left operand x += yx = x + y-=Subtracts the right operand from the left operand and stores the result in the left operand x -= yx = x - y*=Multiplies the right operand with the left operand and stores the result in the left operand x *= yx = x * y/=Divides the left operand by the right operand and stores the result in the left operand x /= yx = x / y//=Performs floor division of the left operand by the right operand and stores the result in the left operand x //= yx = x // y%=Finds the remainder of dividing the left operand by the right operand and stores the result in the left operand x %= yx = x % y**=Raises the left operand to the power of the right operand and stores the result in the left operand x **= yx = x ** yВ столбце Пример приведены общие примеры использования операторов в реальном коде. Обратите внимание, что для корректной работы операторов необходимо предварительно определить
x. С другой стороны,yможет быть либо конкретным значением, либо выражением, возвращающим значение.Примечание: Оператор умножения матрицы (
@) пока не поддерживает расширенные назначения.Рассмотрим следующий пример умножения матриц с использованием массивов NumPy:
>>> import numpy as np >>> x = np.ones(3) >>> x array([1., 1., 1.]) >>> m = np.eye(3) >>> m array([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) >>> x @ m array([1., 1., 1.]) >>> x @= m Traceback (most recent call last): ... TypeError: In-place matrix multiplication is not (yet) supported. Use 'a = a @ b' instead of 'a @= b'.предварительно> кодовый блок>Обратите внимание, что исключение обратная трассировка указывает на то, что операция еще не поддерживается.
Чтобы проиллюстрировать, как работают расширенные операторы присваивания, предположим, что вам нужно создать функцию, которая принимает итерацию числовых значений и возвращает их сумму. Вы можете написать эту функцию, как в приведенном ниже коде:
>>> def sum_all(numbers): ... total = 0 ... for number in numbers: ... total += number # Augmented addition ... return total ... >>> sum_all([1, 2, 3, 4]) 10предварительно> кодовый блок>В этой функции вы сначала инициализируете
totalзначением0. На каждой итерации цикл добавляет новое число кtotal, используя расширенный оператор сложения (+=). Когда цикл завершается,totalсодержит сумму всех входных чисел. Переменные типаtotalизвестны как накопители. Оператор+=обычно используется для обновления накопителей.Примечание: Вычисление суммы ряда числовых значений является обычной операцией в программировании. Python предоставляет встроенную функцию
sum()для этого конкретного вычисления.Еще один интересный пример использования расширенного задания - это когда вам нужно реализовать обратный отсчет
whileцикл для обратного выполнения итерации. В этом случае вы можете использовать оператор-=:>>> def custom_reversed(sequence): ... index = len(sequence) - 1 ... while index >= 0: ... yield sequence[index] ... index -= 1 ... >>> list(custom_reversed("12345")) ['5', '4', '3', '2', '1']предварительно> кодовый блок>В этом примере
custom_reversed()является функцией генератора, поскольку она используетyield. Вызов функции создает итератор, который возвращает элементы из входных данных в обратном порядке. Чтобы уменьшить управляющую переменнуюindex, вы используете расширенный оператор вычитания, который вычитает1из переменной на каждой итерации.Примечание: Аналогично суммированию значений в iterable, изменение значения iterable на обратное также является распространенным требованием. Python предоставляет встроенную функцию
reversed()для этого конкретного вычисления, так что вам не нужно реализовывать свою собственную. Приведенный выше пример предназначен только для того, чтобы показать оператор-=в действии.Наконец, счетчики - это особый тип накопителей, которые позволяют подсчитывать объекты. Вот пример буквенного счетчика:
>>> word = "mississippi" >>> counter = {} >>> for letter in word: ... if letter not in counter: ... counter[letter] = 0 ... counter[letter] += 1 ... >>> counter {'m': 1, 'i': 4, 's': 4, 'p': 2}предварительно> кодовый блок>Чтобы создать этот счетчик, вы используете словарь Python. В ключах хранятся буквы. В значениях хранятся числа. И снова, чтобы увеличить счетчик, вы используете расширенное сложение.
Счетчики настолько распространены в программировании, что Python предоставляет инструмент, специально разработанный для облегчения задачи подсчета. Ознакомьтесь с Счетчик Python: способ подсчета объектов на языке Python для получения полного руководства по использованию этого инструмента.
Расширенные задания для объединения и повторения
Расширенные операторы присваивания
+=и*=также работают с последовательностями, такими как списки, кортежи и строки. Оператор+=выполняет расширенных объединений, в то время как оператор*=выполняет расширенных повторений.Эти операторы по-разному работают с изменяемыми и неизменяемыми типами данных:
Operator Description Example +=Runs an augmented concatenation operation on the target sequence. Mutable sequences are updated in place. If the sequence is immutable, then a new sequence is created and assigned back to the target name. seq_1 += seq_2*=Adds seqto itselfntimes. Mutable sequences are updated in place. If the sequence is immutable, then a new sequence is created and assigned back to the target name.seq *= nОбратите внимание, что расширенный оператор объединения работает с двумя последовательностями, в то время как расширенный оператор повторения работает с последовательностью и целым числом.
Рассмотрим следующие примеры и обратим внимание на результат вызова функции
id():>>> # Mutable target >>> list_1 = [1, 2, 3] >>> id(list_1) 4323479104 >>> list_2 = [4, 5] >>> list_2 [4, 5] >>> list_1 += list_2 # Concatenation... >>> list_1 [1, 2, 3, 4, 5] >>> id(list_1) 4323479104 >>> # Immutable target >>> tuple_1 = (1, 2, 3) >>> id(tuple_1) 4387336896 >>> tuple_2 = (4, 5) >>> tuple_2 (4, 5) >>> tuple_1 += tuple_2 # Concatenation... >>> tuple_1 (1, 2, 3, 4, 5) >>> id(tuple_1) 4387485104предварительно> кодовый блок>Изменяемые последовательности, такие как списки, поддерживают оператор расширенного присваивания
+=с помощью метода.__iadd__(), который выполняет добавление на месте. Этот метод изменяет базовый список, добавляя новые значения в его конец.Примечание: Если левый операнд является изменяемым, то
x += yможет не полностью соответствоватьx = x + y. Например, если вы сделаетеlist_1 = list_1 + list_2вместоlist_1 += list_2, как указано выше, вы создадите новый список, а не измените существующий. Это может быть важно, если другие переменные ссылаются на тот же список.Неизменяемые последовательности, такие как кортежи и строки, не предоставляют метода
.__iadd__(). Таким образом, расширенные объединения возвращаются к методу.__add__(), который не изменяет существующую последовательность, а возвращает новую последовательность.Существует еще одно различие между изменяемыми и неизменяемыми последовательностями, когда вы используете их в расширенной конкатенации. Рассмотрим следующие примеры:
>>> a_list = [1, 2, 3] >>> a_list += (4, 5) >>> a_list [1, 2, 3, 4, 5] >>> a_list += "67" >>> a_list [1, 2, 3, 4, 5, '6', '7'] >>> a_tuple = (1, 2, 3) >>> a_tuple += [4, 5] Traceback (most recent call last): ... TypeError: can only concatenate tuple (not "list") to tuple >>> a_string = "123" >>> a_string += ("4", "5") Traceback (most recent call last): ... TypeError: can only concatenate str (not "tuple") to strпредварительно> кодовый блок>В случае изменяемых последовательностей объединяемые данные могут быть представлены в виде списка, кортежа, строки или любого другого повторяемого файла. В отличие от этого, в случае неизменяемых последовательностей данные могут быть представлены только в виде объектов одного типа. Например, вы можете объединять кортежи в кортежи и строки в строки.
Опять же, оператор расширенного повторения работает с последовательностью в левой части оператора и целым числом в правой части. Это целое значение представляет количество повторений, которое необходимо получить в результирующей последовательности:
>>> # Mutable target >>> a_list = [1, 2, 3] >>> id(a_list) 4395563840 >>> n = 2 >>> a_list *= n # Repetition... >>> a_list [1, 2, 3, 1, 2, 3] >>> id(a_list) 4395563840 >>> a_list[0] is a_list[3] True >>> # Immutable target >>> a_tuple = (1, 2, 3) >>> id(a_tuple) 4393522944 >>> n = 2 >>> a_tuple *= n # Repetition... >>> a_tuple (1, 2, 3, 1, 2, 3) >>> id(a_tuple) 4394199328 >>> a_tuple[0] is a_tuple[3] Trueпредварительно> кодовый блок>Когда оператор
*=работает с изменяемой последовательностью, он возвращается к методу.__imul__(), который выполняет операцию на месте, изменяя базовую последовательность . Напротив, если*=работает с неизменяемой последовательностью, то вызывается.__mul__(), возвращающий новую последовательность того же типа.Примечание: Значения
n, меньшие, чем0, обрабатываются как0, что возвращает пустую последовательность того же значения. введите данные в качестве целевой последовательности в левой части*=операнда.Обратите внимание, что
a_list[0] is a_list[3]возвращаетTrue. Это связано с тем, что оператор*=не создает копию повторяющихся данных. Он только отображает данные. Такое поведение может быть источником проблем при использовании оператора с изменяемыми значениями.Например, предположим, что вы хотите создать список списков для представления матрицы, и вам нужно инициализировать список с помощью
nпустых списков, как в следующем коде:>>> n = 3 >>> matrix = [[]] >>> matrix *= n >>> matrix [[], [], []]предварительно> кодовый блок>В этом примере вы используете оператор
*=для заполненияmatrixтремя пустыми списками. Теперь посмотрите, что происходит, когда вы пытаетесь заполнить первый подсписок вmatrix:>>> matrix[0].append(1) >>> matrix[0].append(2) >>> matrix[0].append(3) >>> matrix [[1, 2, 3], [1, 2, 3], [1, 2, 3]]предварительно> кодовый блок>Добавленные значения отображаются в трех подсписках. Это происходит потому, что оператор
*=не создает копии данных, которые вы хотите повторить. Он отображает только данные. Следовательно, каждый подсписок вmatrixуказывает на один и тот же объект и адрес памяти.Если вам когда-нибудь понадобится инициализировать список с кучей пустых подсписков, то используйте понимание списка:
>>> n = 3 >>> matrix = [[] for _ in range(n)] >>> matrix [[], [], []] >>> matrix[0].append(1) >>> matrix[0].append(2) >>> matrix[0].append(3) >>> matrix [[1, 2, 3], [], []]предварительно> кодовый блок>На этот раз, когда вы заполняете первый подсписок из
matrix, ваши изменения не распространяются на другие подсписки. Это происходит потому, что все подсписки представляют собой разные объекты, которые находятся в разных адресах памяти.Расширенные операторы побитового присваивания
Побитовые операторы также имеют свои расширенные версии. Логика, лежащая в их основе, аналогична логике математических операторов. В следующей таблице приведены расширенные побитовые операторы, предоставляемые Python:
Operator Operation Example Equivalent &=Augmented bitwise AND (conjunction) x &= yx = x & y|=Augmented bitwise OR (disjunction) x |= yx = x | y^=Augmented bitwise XOR (exclusive disjunction) x ^= yx = x ^ y>>=Augmented bitwise right shift x >>= yx = x >> y<<=Augmented bitwise left shift x <<= yx = x << yРасширенные операторы побитового присваивания выполняют требуемую операцию, принимая текущее значение левого операнда в качестве отправной точки для вычисления. Рассмотрим следующий пример, в котором используются операторы
&и&=:>>> number_1 = 123 >>> bin(number_1) '0b1111011' >>> number_2 = 456 >>> bin(number_2) '0b111001000' >>> # Bitwise AND >>> # 0b1111011 (int 123) >>> # & 0b111001000 (int 456) >>> # ------------- >>> # 0b1001000 (int 72) >>> number_1 & number_2 72 >>> bin(number_1 & number_2) '0b1001000' >>> number_1 &= number_2 >>> number_1 72 >>> bin(number_1) '0b1001000'предварительно> кодовый блок>Программисты, работающие с языками высокого уровня, такими как Python, редко используют побитовые операции в повседневном программировании. Однако в некоторых ситуациях эти типы операций могут быть полезны.
Например, предположим, что вы внедряете систему разрешений в стиле Unix, позволяющую вашим пользователям получать доступ к данному ресурсу. В этом случае вы можете использовать символы
"r"для чтения,"w"для записи и"x"для разрешений на выполнение, соответственно. Однако использование битовых разрешений может повысить эффективность использования памяти:>>> r = 0b100 >>> w = 0b010 >>> x = 0b001 >>> # Assign permissions to users with | >>> admin = r | w | x >>> bin(admin) '0b111' >>> # Assign permissions to users with |= >>> user = r >>> user |= w >>> bin(user) '0b110' >>> # Check permission with & and bool() >>> bool(r & user) True >>> bool(x & user) Falseпредварительно> кодовый блок>Вы можете назначать разрешения своим пользователям с помощью побитового оператора OR или расширенного побитового оператора OR. Наконец, вы можете использовать побитовый оператор AND, чтобы проверить, есть ли у пользователя определенные права доступа, как вы делали в последних двух примерах.
В этом и предыдущих разделах вы узнали много нового об операторах расширенного присваивания и инструкциях. Эти операторы применимы к математическим операциям, конкатенации, повторению и побитовым операциям. Теперь вы готовы рассмотреть другие варианты назначения, которые вы можете использовать в своем коде или найти в коде других разработчиков.
Другие варианты назначения
Итак, вы узнали, что операторы присваивания в Python и оператор присваивания присутствуют во многих различных сценариях и вариантах использования. Эти варианты использования включают создание и инициализацию переменных, параллельные назначения, итеративную распаковку, расширенные назначения и многое другое.
В следующих разделах вы узнаете о нескольких вариантах инструкций присваивания, которые могут быть полезны в вашем будущем программировании. Вы также можете найти эти варианты присваивания в коде других разработчиков. Поэтому вы должны быть осведомлены о них и знать, как они работают на практике.
Вкратце, вы узнаете о:
- Аннотированные инструкции присваивания с подсказками по типу
- Выражения присваивания с помощью оператора walrus
- Управляемых назначений атрибутов с помощью свойств и дескрипторов
- Неявные присваивания в Python
В этих разделах вы познакомитесь с несколькими интересными и полезными примерами, демонстрирующими мощь операторов присваивания в Python.
Аннотированные операторы присваивания
PEP 526 ввел специальный синтаксис для аннотаций переменных еще в Python 3.6. Синтаксис состоит из имени переменной, за которым следует двоеточие (
:), и типа переменной:>>> counter: int >>> name: str >>> fruits: list[str]предварительно> кодовый блок>Несмотря на то, что эти операторы объявляют три переменные с соответствующими типами данных, на самом деле они не создаются и не инициализируются. Так, например, вы не можете использовать ни одну из этих переменных в расширенном операторе присваивания:
>>> counter += 1 Traceback (most recent call last): ... NameError: name 'counter' is not definedпредварительно> кодовый блок>Если вы попытаетесь использовать одну из ранее объявленных переменных в расширенном присваивании, то получите
NameError, поскольку синтаксис аннотации не определяет переменную. Чтобы на самом деле определить это, вам нужно использовать присваивание.Хорошей новостью является то, что вы можете использовать синтаксис аннотации переменной в операторе присваивания с помощью оператора
=:>>> counter: int = 0 >>> counter += 1 >>> counter += 1 >>> counter 2предварительно> кодовый блок>Первый оператор в этом примере - это то, что вы можете назвать аннотированным оператором присваивания в Python. Вы можете спросить себя, зачем вам использовать аннотации типов в этом типе задания, если все могут видеть, что
counterсодержит целое число. Ты прав. В этом примере тип переменной однозначен.Однако представьте, что произошло бы, если бы вы нашли инициализацию переменной, подобную следующей:
>>> class User: ... # Class implementation... ... pass ... >>> users = []предварительно> кодовый блок>Каким будет тип данных каждого пользователя в
users? Если инициализацияusersдалека от определения классаUser, то нет быстрого способа ответить на этот вопрос. Чтобы прояснить эту двусмысленность, вы можете предоставить соответствующую подсказку по типу дляusers:>>> class User: ... # Class implementation... ... pass ... >>> users: list[User] = []предварительно> кодовый блок>Теперь вы четко указываете, что
usersбудет содержать списокUserэкземпляров. Использование подсказок о типах в операторах присваивания, которые инициализируют переменные в пустые типы данных коллекции, такие как списки, кортежи или словари, позволяет вам предоставить больше информации о том, как работает ваш код. Это сделает ваш код более понятным и менее подверженным ошибкам.Выражения присваивания с помощью оператора Walrus
До этого момента вы знали, что обычные инструкции присваивания с оператором
=не имеют возвращаемого значения. Они просто создают или обновляют переменные. Следовательно, вы не можете использовать обычное присваивание для присвоения значения переменной в контексте выражения.Python 3.8 изменил это, введя новый тип оператора присваивания в PEP 572. Это новое выражение известно как выражение присваивания или именованное выражение.
Примечание: Выражения - это особый тип операторов в Python. Их отличительной особенностью является то, что выражения всегда имеют возвращаемое значение, что характерно не для всех типов операторов.
В отличие от обычных присваиваний, выражения присваивания имеют возвращаемое значение, поэтому они и называются выражениями. Это возвращаемое значение автоматически присваивается переменной. Чтобы написать выражение присваивания, вы должны использовать оператор walrus (
:=),, который был назван так из-за его сходства с глазами и бивнями моржа, лежащего на боку.Общий синтаксис оператора присваивания следующий:
(variable := expression)предварительно> кодовый блок>Это выражение выглядит как обычное присваивание. Однако вместо оператора присваивания (
=), в нем используется оператор walrus (:=). Для корректной работы выражения в большинстве случаев требуются заключительные скобки. Однако существуют определенные ситуации, в которых эти скобки излишни. В любом случае, они вам не повредят.Выражения присваивания удобны, когда вы хотите повторно использовать результат выражения или его часть без использования специального присваивания для предварительного получения этого значения.
Примечание: Выражения присваивания с оператором walrus имеют несколько практических вариантов использования. У них также есть несколько ограничений. Например, они недопустимы в определенных контекстах, таких как
lambdaфункции, параллельные назначения и расширенные назначения.Чтобы более подробно ознакомиться с этим особым типом присваивания, ознакомьтесь с Оператором Walrus: выражениями присваивания в Python..
Особенно удобный вариант использования выражений присваивания - это когда вам нужно получить результат выражения, используемого в контексте условного оператора. Например, предположим, что вам нужно написать функцию для вычисления среднего значения выборки числовых значений. Без оператора walrus вы могли бы сделать что-то вроде этого:
>>> def mean(sample): ... n = len(sample) ... if n == 0: ... raise ValueError("input data required") ... return sum(sample) / n ... >>> mean([1, 2, 3, 4, 5]) 3.0предварительно> кодовый блок>В этом примере размер выборки (
n) - это значение, которое необходимо повторно использовать в двух разных вычислениях. Во-первых, вам нужно проверить, содержит ли выборка точки данных или нет. Затем вам нужно использовать размер выборки для вычисления среднего значения. Чтобы иметь возможность повторно использоватьn, вы написали специальную инструкцию присваивания в начале своей функции, чтобы получить размер выборки.Вы можете избежать этого дополнительного шага, объединив его с первым использованием целевого значения
len(sample), используя выражение присваивания, подобное следующему:>>> def mean(sample): ... if (n := len(sample)) == 0: ... raise ValueError("input data required") ... return sum(sample) / n ... >>> mean([1, 2, 3, 4, 5]) 3.0предварительно> кодовый блок>Выражение присваивания, введенное в условное обозначение, вычисляет размер выборки и присваивает ему значение
n. Таким образом, вы гарантируете, что у вас есть ссылка на размер выборки для использования в дальнейших вычислениях.Поскольку выражение присваивания в любом случае возвращает размер выборки, условие может проверить, равен ли этот размер
0или нет, а затем предпринять определенные действия в зависимости от результата этой проверки. Операторreturnвычисляет среднее значение выборки и отправляет результат обратно вызывающей функции.Назначение управляемых атрибутов
Python предоставляет несколько инструментов, которые позволяют вам точно настроить операции, стоящие за назначением атрибутов. Атрибуты, которые выполняют неявные операции с назначениями, обычно называются управляемыми атрибутами.
Свойства являются наиболее часто используемым инструментом для предоставления управляемых атрибутов в ваших классах. Однако вы также можете использовать дескрипторы и, в некоторых случаях, специальный метод
.__setitem__().Чтобы понять, что означает тонкая настройка операции, стоящей за присваиванием, предположим, что вам нужен
Pointкласс, который допускает только числовые значения для своих координат,xиy. Чтобы написать этот класс, вы должны настроить механизм проверки, чтобы отклонять нечисловые значения. Вы можете использовать свойства, чтобы добавить функциональность проверки поверхxиy.Вот как вы можете написать свой класс:
# point.py class Point: @property def x(self): return self._x @x.setter def x(self, value): try: self._x = float(value) except ValueError: raise ValueError('"x" must be a number') from None @property def y(self): return self._y @y.setter def y(self, value): try: self._y = float(value) except ValueError: raise ValueError('"y" must be a number') from Noneпредварительно> кодовый блок>В
Pointиспользуются свойства для координат.xи.y. У каждого свойства есть получатель и метод установки. Метод получения возвращает соответствующий атрибут. Метод setter выполняет проверку введенных данных с использованием блокаtry...exceptи встроенной функцииfloat(). Затем метод присваивает результат фактическому атрибуту.Вот как работает ваш класс на практике:
>>> from point import Point >>> point_1 = Point() >>> point_1.x = 1 >>> point_1.y = 2 >>> point_1.x, point_1.y 1.0 2.0 >>> point_2 = Point() >>> point_2.x = "one" Traceback (most recent call last): ... ValueError: "x" must be a numberпредварительно> кодовый блок>Когда вы используете атрибут, основанный на свойстве, в качестве левого операнда в операторе присваивания, Python автоматически вызывает метод setter для этого свойства, выполняя с его помощью любые вычисления.
Поскольку и
.x, и.yявляются свойствами, проверка ввода выполняется всякий раз, когда вы присваиваете значение любому из атрибутов. В первом примере входные значения являются допустимыми числами, и проверка проходит успешно. В последнем примере"one"не является допустимым числовым значением, поэтому проверка завершается неудачей.Если вы посмотрите на свой класс
Point, вы заметите, что он следует повторяющемуся шаблону, а методы получения и установки выглядят довольно похожими. Чтобы избежать этого повторения, вы можете использовать дескриптор вместо свойства.Дескриптор - это класс, реализующий протокол дескриптора, который состоит из четырех специальных методов:
.__get__()запускается при обращении к атрибуту, представленному дескриптором..__set__()выполняется при использовании атрибута в инструкции присваивания..__delete__()выполняется при использовании атрибута в инструкцииdel..__set_name__()задает имя атрибута, создавая атрибут, зависящий от имени.Вот как может выглядеть ваш код, если вы используете дескриптор для представления координат вашего класса
Point:# point.py class Coordinate: def __set_name__(self, owner, name): self._name = name def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): try: instance.__dict__[self._name] = float(value) except ValueError: raise ValueError(f'"{self._name}" must be a number') from None class Point: x = Coordinate() y = Coordinate()предварительно> кодовый блок>Вы удалили повторяющийся код, определив
Coordinateв качестве дескриптора, который управляет проверкой ввода в одном месте. Продолжайте и запустите следующий код, чтобы опробовать новую реализациюPoint:>>> from point import Point >>> point_1 = Point() >>> point_1.x = 1 >>> point_1.y = 2 >>> point_1.x, point_1.y 1.0 2.0 >>> point_2 = Point() >>> point_2.x = "one" Traceback (most recent call last): ... ValueError: "x" must be a numberпредварительно> кодовый блок>Отлично! Класс работает так, как ожидалось. Благодаря дескриптору
Coordinateтеперь у вас есть более сжатая и неповторяющаяся версия исходного кода.Другой способ тонкой настройки операций, лежащих в основе оператора присваивания, - это предоставить пользовательскую реализацию
.__setitem__()в вашем классе. Вы будете использовать этот метод в классах, представляющих изменяемые коллекции данных, таких как пользовательские классы, похожие на списки или классы, похожие на словари.В качестве примера предположим, что вам нужно создать класс, подобный словарю, который хранит свои ключи строчными буквами:
>>> from collections import UserDict >>> class LowerCasedDict(UserDict): ... def __setitem__(self, key, value): ... key = key.lower() ... super().__setitem__(key, value) ... >>> numbers = LowerCasedDict() >>> numbers["ONE"] = 1 >>> numbers["Two"] = 2 >>> numbers["Three"] = 3 >>> numbers {'one': 1, 'two': 2, 'three': 3}предварительно> кодовый блок>В этом примере вы создаете класс, подобный словарю, путем создания подкласса
UserDictизcollections. Ваш класс реализует метод.__setitem__(), который принимаетkeyиvalueв качестве аргументов. Метод используетstr.lower()для преобразованияkeyв строчные буквы перед сохранением в базовом словаре.Python неявно вызывает
.__setitem__()каждый раз, когда вы используете ключ в качестве левого операнда в операторе присваивания. Такое поведение позволяет вам настроить процесс присвоения ключей в вашем пользовательском словаре.Неявные присваивания в Python
Python неявно выполняет присваивания в самых разных контекстах. В большинстве случаев эти неявные присваивания являются частью синтаксиса языка. В других случаях они поддерживают определенное поведение.
Всякий раз, когда вы выполняете действие из следующего списка, Python выполняет для вас неявное назначение:
- Определите или вызовите функцию
- Определите или создайте экземпляр класса
- Используйте текущий экземпляр ,
self- Импорт модулей и объектов
- Используйте декоратор
- Используйте управляющую переменную в цикле
forили для понимания- Используйте определитель
asв операторахwith, imports иtry...exceptblocks- Получить доступ к специальной переменной
_в интерактивном сеансеЗа кулисами Python выполняет задание в каждой из вышеперечисленных ситуаций. В следующих подразделах вы познакомитесь со всеми этими ситуациями.
Определить или вызвать функцию
Когда вы определяете функцию, ключевое слово
defнеявно присваивает объекту функции имя вашей функции. Вот пример:>>> def greet(name): ... print(id(name)) ... print(f"Hello, {name}!") ... >>> greet <function greet at 0x105e9bb00> >>> id(greet) 4394171136 >>> fellow = "Pythonista" >>> greet(fellow) 4381781552 Hello, Pythonista! >>> id(fellow) 4381781552предварительно> кодовый блок>С этого момента имя
greetотносится к объекту функции, который находится по заданному адресу в памяти вашего компьютера. Вы можете вызвать функцию, используя ее имя и пару круглых скобок с соответствующими аргументами. Таким образом, вы можете повторно использоватьgreet()везде, где вам это нужно.Если вы вызываете свою функцию
greet()сfellowв качестве аргумента, то Python неявно присваивает значение входного аргумента параметруnameв определении функции. Параметр будет содержать ссылку на входные аргументы.Работа с Классами
Когда вы определяете класс с помощью ключевого слова
class, вы присваиваете конкретное имя объекту класса . Позже вы сможете использовать это имя для создания экземпляров этого класса. Рассмотрим следующий пример:>>> class User: ... def __init__(self, name, job): ... self.name = name ... self.job = job ... >>> User <class '__main__.User'> >>> id(User) 5035278528 >>> john = User("John Doe", "Python Dev") >>> john.name 'John Doe' >>> john.job 'Python Dev'предварительно> кодовый блок>В этом примере имя
Userсодержит ссылку на объект класса, который был определен в__main__.User. Как и в случае с функцией, когда вы вызываете конструктор класса с соответствующими аргументами для создания экземпляра, Python присваивает аргументы параметрам, определенным в классе инициализаторе.Другим примером неявных назначений является текущий экземпляр класса, который в Python называется
selfпо соглашению. Это имя неявно содержит ссылку на текущий объект всякий раз, когда вы создаете экземпляр класса. Благодаря этому неявному присваиванию вы можете получить доступ к.nameи.jobиз класса, не получаяNameErrorв своем коде.Импорт модулей и объектов
Инструкции Import - это еще один вариант неявных назначений в Python. С помощью инструкции import вы присваиваете имя объекту модуля, классу, функции или любому другому импортируемому объекту. Затем это имя создается в вашем текущем пространстве имен, чтобы вы могли получить к нему доступ позже в своем коде:
>>> dir() ['__builtins__', '__doc__', ..., '__spec__', 'help'] >>> import sys >>> dir() ['__builtins__', '__doc__', ..., '__spec__', 'help', 'sys'] >>> sys <module 'sys' (built-in)>предварительно> кодовый блок>В этом примере вы импортируете объект
sysmodule из стандартной библиотеки и присваиваете ему имяsys, которое теперь доступно в вашем пространстве имен, как вы можете заключить из второго вызова встроенного модуля.- в функцииdir().Используйте декоратор
Вы также выполняете неявное присваивание, когда используете декоратор в своем коде. Синтаксис декоратора - это просто ярлык для формального присваивания, подобного следующему:
func = decorator(func)предварительно> кодовый блок>Здесь вы вызываете
decorator(), используя объект функции в качестве аргумента. Этот вызов обычно добавляет функциональность поверх существующей функцииfunc()и возвращает объект функции, которому затем присваивается имяfunc.Синтаксис декоратора - это синтаксический сахар для замены предыдущего задания, которое теперь вы можете записать следующим образом:
@decorator def func(): # Implementation here... passпредварительно> кодовый блок>Несмотря на то, что этот новый код внешне сильно отличается от приведенного выше задания, в нем неявно выполняются те же действия.
Доступ к управляющей переменной осуществляется в цикле
forили в режиме пониманияДругая ситуация, в которой Python автоматически выполняет неявное присваивание, - это когда вы используете
forцикл или понимание. В обоих случаях у вас может быть одна или несколько управляющих переменных, которые вы затем используете в цикле или в тексте описания:>>> for control_variable in range(5): ... print(f"{control_variable=} {id(control_variable)=}") ... control_variable=0 id(control_variable)=4376944840 control_variable=1 id(control_variable)=4376944872 control_variable=2 id(control_variable)=4376944904 control_variable=3 id(control_variable)=4376944936 control_variable=4 id(control_variable)=4376944968предварительно> кодовый блок>Адрес памяти
control_variableизменяется на каждой итерации цикла. Это происходит потому, что Python внутренне присваивает новое значение из iterable цикла управляющей переменной цикла в каждом цикле.То же самое происходит в понятиях:
>>> [ ... f"{control_variable=} {id(control_variable)=}" ... for control_variable in range(5) ... ] [ 'control_variable=0 id(control_variable)=4376944840', 'control_variable=1 id(control_variable)=4376944872', 'control_variable=2 id(control_variable)=4376944904', 'control_variable=3 id(control_variable)=4376944936', 'control_variable=4 id(control_variable)=4376944968' ]предварительно> кодовый блок>В конечном счете, понимание работает как цикл
for, но использует более сжатый синтаксис. Это понимание создает новый список строк, который имитирует вывод из предыдущего примера.Используйте ключевое слово
asКлючевое слово
asвwithутверждения,exceptпредложений иimportутверждений - это еще одно пример неявного присваивания в Python. На этот раз назначение не является полностью неявным, поскольку ключевое словоasпредоставляет явный способ определения целевой переменной.В инструкции
withцелевая переменная, следующая за ключевым словомas, будет содержать ссылку на контекстный менеджер, с которым вы работаете. В качестве примера предположим, что у вас естьhello.txtфайл со следующим содержимым:Hello, Pythonista! Welcome to Real Python!предварительно> кодовый блок>Вы хотите открыть этот файл и вывести каждую его строку на экран. В этом случае вы можете воспользоваться инструкцией
with, чтобы открыть файл с помощью встроенной функцииopen().В приведенном ниже примере вы выполняете это. Вы также добавляете несколько вызовов в
print(), которые отображают информацию о целевой переменной, определенной ключевым словомas:>>> with open("hello.txt", mode="r") as hello: ... print(f"File object: {hello}") ... print(f"Memory address: {id(hello)}") ... print("File content:") ... for line in hello: ... print("> ", line) ... File object: <_io.TextIOWrapper name='hello.txt' mode='r' encoding='UTF-8'> Memory address: 4372378896 File content: > Hello, Pythonista! > Welcome to Real Python!предварительно> кодовый блок>Этот оператор
withиспользует функциюopen()для открытияhello.txt. Функцияopen()является контекстным менеджером, который возвращает объект текстового файла, представленный экземпляромio.TextIOWrapper.Поскольку вы определили целевую переменную
helloс ключевым словомas, теперь эта переменная содержит ссылку на сам файловый объект. Вы подтверждаете это, выводя объект и его адрес в памяти. Наконец, циклforвыполняет итерацию по строкам и выводит это содержимое на экран.Когда дело доходит до использования ключевого слова
asв контексте предложенияexcept, целевая переменная будет содержать объект exception, если возникнет какое-либо исключение:>>> try: ... 5 / 0 ... except ZeroDivisionError as error: ... print(f"Exception: {error}") ... print(f"Memory address: {id(error)}") ... Exception: division by zero Memory address: 4382188704 >>> error Traceback (most recent call last): ... NameError: name 'error' is not definedпредварительно> кодовый блок>В этом примере выполняется разделение, при котором возникает
ZeroDivisionError. Ключевое словоasприсваивает возникшему исключению значениеerror. Обратите внимание, что при печати объекта exception вы получаете только сообщение, потому что исключения имеют пользовательский метод.__str__(), который поддерживает это поведение.Есть еще одна деталь, о которой следует помнить при использовании спецификатора
asв блокеtry...except, подобном приведенному в примере выше. Как только вы покидаете блокexcept, целевая переменная выходит за пределы области , и вы больше не можете ее использовать.Наконец, операторы
importв Python также поддерживают ключевое словоas. В этом контексте вы можете использоватьasдля импорта объектов с другим именем:>>> import numpy as np >>> import pandas as pd >>> dir() ['__builtins__', '__doc__', ..., 'help', 'np', 'pd']предварительно> кодовый блок>В этих примерах вы используете ключевое слово
asдля импорта пакетаnumpyс именемnpиpandasс именемpd. Если вы вызоветеdir(), то поймете, чтоnpиpdтеперь находятся в вашем пространстве имен. Однако именаnumpyиpandasтаковыми не являются.Использование ключевого слова
asв вашем импорте удобно, когда вы хотите использовать более короткие имена для своих объектов или когда вам нужно использовать разные объекты, которые изначально имели одинаковое имя в вашем коде. Это также полезно, если вы хотите сделать импортированные имена непубличными, используя начальное подчеркивание, как вimport sys as _sys.Доступ к специальной переменной
_в интерактивном сеансеОкончательное неявное назначение, о котором вы узнаете в этом руководстве, выполняется только при использовании Python в интерактивном сеансе. Каждый раз, когда вы запускаете инструкцию, возвращающую значение, интерпретатор сохраняет результат в специальной переменной, обозначаемой одним символом подчеркивания (
_).Вы можете получить доступ к этой специальной переменной так же, как к любой другой переменной:
>>> # Expressions >>> 5 < 7 True >>> _ True >>> 12 + 30 42 >>> _ 42 >>> # Function calls >>> sum([1, 2, 3, 4]) 10 >>> _ 10 >>> print("Hello, Pythonista!") Hello, Pythonista! >>> _ 10 >>> # Assignments >>> counter = 0 >>> _ 10 >>> # Variable accesses >>> counter 0 >>> _ 0предварительно> кодовый блок>Эти примеры охватывают несколько ситуаций, в которых Python внутренне использует переменную
_. В первых двух примерах вычисляются выражения. Выражения всегда имеют возвращаемое значение, которое каждый раз автоматически присваивается переменной_.Когда дело доходит до вызовов функций, обратите внимание, что если ваша функция возвращает результативное значение, то оно будет сохранено в
_. Напротив, если ваша функция возвращает значениеNone,, то переменная_останется нетронутой.Следующий пример состоит из обычной инструкции присваивания. Как вы уже знаете, обычные присваивания не возвращают никакого значения, поэтому переменная
_не обновляется после выполнения этих инструкций. Наконец, обратите внимание, что при обращении к переменной в интерактивном сеансе возвращается значение, сохраненное в целевой переменной. Затем это значение присваивается переменной_.Обратите внимание, что поскольку
_является обычной переменной, вы можете использовать ее в других выражениях:>>> numbers = [1, 2, 3, 4] >>> len(numbers) 4 >>> sum(numbers) / _ 2.5предварительно> кодовый блок>В этом примере сначала создается список значений. Затем вызывается
len(), чтобы получить количество значений в списке. Python автоматически сохраняет это значение в переменной_. Наконец, вы используете_для вычисления среднего значения из вашего списка значений.Теперь, когда вы узнали о некоторых неявных назначениях, которые реализованы в Python, пришло время перейти к последнему разделу, связанному с назначениями. В следующих нескольких разделах вы узнаете о некоторых незаконных и опасных назначениях, о которых вам следует знать и избегать в своем коде.
Незаконные и опасные задания в Python
В Python вы найдете несколько ситуаций, в которых использование присваиваний либо запрещено, либо опасно. Вы должны знать об этих особых ситуациях и стараться избегать их в своем коде.
В следующих разделах вы узнаете, когда использование инструкций присваивания запрещено в Python. Вы также узнаете о некоторых ситуациях, в которых следует избегать использования присваиваний, если вы хотите сохранить согласованность и надежность своего кода.
Ключевые слова
Вы не можете использовать ключевые слова Python в качестве имен переменных в операторах присваивания. Этот вид присваивания явно запрещен. Если вы попытаетесь использовать ключевое слово в качестве имени переменной в задании, то получите
SyntaxError:>>> class = "Economy" File "<stdin>", line 1 class = "Economy" ^ SyntaxError: invalid syntax >>> global = 42 File "<input>", line 1 global = 42 ^ SyntaxError: invalid syntaxпредварительно> кодовый блок>Всякий раз, когда вы пытаетесь использовать ключевое слово в качестве левого операнда в операторе присваивания, вы получаете
SyntaxError. Ключевые слова являются неотъемлемой частью языка и не могут быть переопределены.Если вы когда-нибудь почувствуете необходимость присвоить одной из ваших переменных имя, используя ключевое слово Python, вы можете добавить к имени вашей переменной символ подчеркивания:
>>> class_ = "Economy" >>> class_ 'Economy' >>> global_ = 42 >>> global_ 42предварительно> кодовый блок>В этом примере вы используете желаемое имя для своих переменных. Поскольку вы добавили последнее подчеркивание к именам, Python не распознает их как ключевые слова, поэтому ошибка не возникает.
Примечание: Несмотря на то, что добавление символа подчеркивания в конце имени является официально рекомендуемой практикой , иногда это может привести к путанице. Поэтому старайтесь найти альтернативное название или использовать синоним всякий раз, когда вы сталкиваетесь с использованием этого соглашения.
Например, вы можете написать что-то вроде этого:
>>> booking_class = "Economy" >>> booking_class 'Economy'предварительно> кодовый блок>В этом примере использование имени
booking_classдля вашей переменной намного понятнее и нагляднее, чем использованиеclass_.Вы также обнаружите, что в операторе присваивания можно использовать только несколько ключевых слов как часть правильного операнда. Эти ключевые слова обычно определяют простые операторы, которые возвращают значение или объект. К ним относятся
lambda,and,or,not,True,False,None,in, иis. Вы также можете использовать ключевое словоfor, когда оно является частью понимания, и ключевое словоif, когда оно используется как часть троичного оператора .В присваивании вы никогда не сможете использовать составной оператор в качестве правильного операнда. Составные инструкции - это те, для которых требуется блок с отступом, такие как
forиwhileциклы, условные выражения,withинструкции,try...exceptблоки и определения классов или функций.Встроенные объекты
Иногда вам нужно присвоить переменным имена, но желаемое или идеальное имя уже занято и используется как встроенное. Если это ваш случай, подумайте хорошенько и найдите другое имя. Не затеняйте встроенное устройство.
Скрытие встроенных имен может привести к трудноопределимым проблемам в вашем коде. Распространенным примером этой проблемы является использование
listилиdictдля присвоения имен пользовательским переменным. В этом случае вы переопределяете соответствующие встроенные имена, которые не будут работать должным образом, если вы будете использовать их позже в своем коде.Рассмотрим следующий пример:
>>> list = [1, 2, 3, 4] >>> squares = list(map(lambda x: x ** 2, [1, 2, 3, 4])) Traceback (most recent call last): ... TypeError: 'list' object is not callableпредварительно> кодовый блок>Исключение в этом примере может показаться неожиданным. Почему вы не можете использовать
list()для создания списка из вызоваmap(), который возвращает генератор квадратных чисел?Используя имя
listдля идентификации вашего списка чисел, вы скрыли встроенное имяlist. Теперь это имя указывает на объект списка, а не на встроенный класс. Объекты списка недоступны для вызова, поэтому ваш код больше не работает.В Python нет ничего, что бы предостерегало от использования встроенных, стандартных библиотек или даже соответствующих имен сторонних разработчиков для идентификации ваших собственных переменных. Поэтому вам следует внимательно следить за этой практикой. Это может быть источником трудно поддающихся отладке ошибок.
Именованные константы
В программировании константой называется имя, связанное со значением, которое никогда не меняется во время выполнения программы. В отличие от других языков программирования, в Python нет специального синтаксиса для определения констант. Этот факт подразумевает, что в Python нет констант в строгом смысле этого слова.
В Python есть только переменные. Если вам нужна константа в Python, вам нужно будет определить переменную и гарантировать, что она не изменится во время выполнения вашего кода. Чтобы сделать это, вы должны избегать использования этой переменной в качестве левого операнда в операторе присваивания.
Чтобы сообщить другим программистам на Python, что данная переменная должна рассматриваться как константа, вы должны написать название своей переменной заглавными буквами с подчеркиванием, разделяющим слова. Это соглашение об именовании было принято сообществом Python и является рекомендацией, которую вы найдете в разделе Константы в PEP 8.
В следующих примерах вы определяете некоторые константы в Python:
>>> PI = 3.14 >>> MAX_SPEED = 300 >>> WIDTH = 20 >>> BASE_URL = "https://api.example.com"предварительно> кодовый блок>Проблема с этими константами заключается в том, что они на самом деле являются переменными. Ничто не мешает вам изменять их значение во время выполнения вашего кода. Таким образом, в любой момент вы можете сделать что-то вроде следующего:
>>> PI = 3.141592653589793 >>> MAX_SPEED = 1_000предварительно> кодовый блок>Эти назначения изменяют значения двух ваших исходных констант. Python не жалуется на эти изменения, которые могут вызвать проблемы в дальнейшем в вашем коде. Как разработчик Python, вы должны гарантировать, что именованные константы в вашем коде остаются неизменными.
Единственный способ сделать это - никогда не использовать именованные константы в операторе присваивания, кроме определения константы.
Заключение
Вы много узнали об операторах присваивания в Python и о том, как их использовать для написания операторов присваивания. С помощью этого типа инструкций вы можете создавать, инициализировать и обновлять переменные в соответствии со своими потребностями. Теперь у вас есть необходимые навыки для полноценного управления созданием и изменением переменных в вашем коде на Python.
В этом руководстве вы узнали, как:
- Напишите инструкции присваивания, используя операторы присваивания в Python
- Работа с дополненными заданиями в Python
- Изучите варианты присвоения, такие как выражение присвоения и управляемые атрибуты
- Выявлять незаконные и опасные назначения в Python
Изучение оператора присваивания Python и того, как его использовать в операторах присваивания, является фундаментальным навыком в Python. Это позволит вам писать надежный и эффективный код на Python.
Бесплатный исходный код: Нажмите здесь, чтобы скачать бесплатный исходный код оператора присваивания, который вы будете использовать для написания инструкций присваивания, позволяющих вам создавать, инициализировать и обновлять переменные в вашем коде.
<статус завершения article-slug="python-assignment-operator" class="btn-group mb-0" data-api-article-bookmark-url="/api/v1/articles/python-assignment-operator/bookmark/" данные-api-article-завершение-status-url="/api/v1/articles/python-оператор присваивания/завершение_статуса/"> статус завершения> <кнопка поделиться bluesky-text="Интересная статья на #Python от @realpython.com :" email-body="Ознакомьтесь с этой статьей о Python:%0A%0apython's Assignment Operator: Пишите надежные задания" email-subject="Статья о Python для вас" twitter-text="Интересная статья о #Python от @realpython:" url="https://realpython.com/python-assignment-operator /" url-title="Оператор присваивания в Python: запись надежных присваиваний"> кнопка поделиться> Back to Top