Присваивание и ссылки в Python

PythonBeginner
Практиковаться сейчас

Введение

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

Введение в присвоения в Python

В Python присвоение - это процесс связывания имени с объектом. Статements присвоения имеют следующий общий вид:

variable = expression

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

Посмотрим на простой пример:

Простой тест

Откройте Терминал и введите в терминале следующую команду.

python3

Затем введите следующий код.

## Присвойте значение 42 переменной 'x' и выведите его.
x = 42
print(x)

Результат:

42

Здесь мы присваиваем переменной x значение 42 с помощью оператора =. Затем мы выводим значение x.

Понимание ссылок

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

Вот пример, иллюстрирующий этот концепт:

## Демонстрирует ссылки в Python.
x = [1, 2, 3]
y = x
y.append(4)

print("x:", x)
print("y:", y)

Результат:

x: [1, 2, 3, 4]
y: [1, 2, 3, 4]

В этом примере как x, так и y ссылаются на один и тот же объект списка. Когда мы изменяем список по ссылке y, добавляя 4, изменения отражаются и в x, и в y.

Изменяемые и неизменяемые объекты

В Python есть два типа объектов: изменяемые и неизменяемые.

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

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

Посмотрим на пример, демонстрирующий разницу между изменяемыми и неизменяемыми объектами:

## Пример изменяемого объекта
mutable_list = [1, 2, 3]
another_mutable_list = mutable_list
another_mutable_list.append(4)
print("mutable_list:", mutable_list)

Результат:

mutable_list: [1, 2, 3, 4]

mutable_list добавляет 4 в конец списка, потому что это изменяемый объект, но неизменяемые объекты не могут быть изменены после их создания.

## Пример неизменяемого объекта
immutable_string = "hello"
another_immutable_string = immutable_string
another_immutable_string = another_immutable_string.upper()
print("immutable_string:", immutable_string)

Результат:

immutable_string: hello

Ничего не меняется, и если мы хотим изменить immutable_string следующим образом, Python-интерпретатор вызовет ошибку TypeError:

immutable_string[0] = '1'

Результат:

TypeError: 'str' object does not support item assignment

Примеры

Посмотрим на несколько более примеров, чтобы укрепить концепции, которые мы выучили:

Пример 1: Функция с изменяемым аргументом по умолчанию

Избегайте использования изменяемых объектов в качестве аргументов по умолчанию в функциях:

def bad_append(new_item, a_list=[]):
    a_list.append(new_item)
    return a_list

print(bad_append('one'))

Результат:

['one']

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

print(bad_append('two'))

Результат:

['one', 'two']

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

def append_to_list(item: int, a_list: list = None) -> list:
    """Добавляет элемент в список и возвращает обновленный список."""
    if a_list is None:
        a_list = []
    a_list.append(item)
    return a_list

list_a = append_to_list(1, [1, 2, 3])
print(list_a)

Результат:

[1, 2, 3, 1]

Пример 2: Копирование изменяемых объектов

Используйте модуль copy, чтобы создать новый объект, когда вы хотите работать с копией изменяемого объекта:

import copy

## Демонстрирует использование модуля copy.
original_list = [1, 2, 3]
copied_list = copy.copy(original_list)
copied_list.append(4)

print("original_list:", original_list)
print("copied_list:", copied_list)

Результат:

original_list: [1, 2, 3]
copied_list: [1, 2, 3, 4]

В этом примере copied_list - это новый объект, являющийся копией original_list. Когда мы добавляем 4 в copied_list, original_list остается неизменным.

Пример 3: Глубокое копирование изменяемых объектов

Для вложенных изменяемых объектов использование функции copy не работает:

## ваш пример с копированием здесь
original_nested_list = [[1, 2], [3, 4]]
copied_nested_list = copy.copy(original_nested_list)
copied_nested_list[0].append(5)

print("original_nested_list:", original_nested_list)
print("copied_nested_list:", copied_nested_list)

Результат:

original_nested_list: [[1, 2, 5], [3, 4]]
copied_nested_list: [[1, 2, 5], [3, 4]]

Мы видим, что когда мы добавляем 5 в copied_nested_list, original_nested_list также добавляет 5. Поэтому вы должны использовать функцию deepcopy вместо этого:

## ваш пример с deepcopy здесь
original_nested_list = [[1, 2], [3, 4]]
deep_copied_list = copy.deepcopy(original_nested_list)
deep_copied_list[0].append(5)

print("original_nested_list:", original_nested_list)
print("deep_copied_list:", deep_copied_list)

Результат:

original_nested_list: [[1, 2], [3, 4]]
deep_copied_list: [[1, 2, 5], [3, 4]]

В этом примере функция deepcopy рекурсивно копирует original_nested_list, в то время как функция copy создает ссылку на первый уровень данных original_nested_list.

Резюме

В этом руководстве по программированию на Python мы рассмотрели основы присвоения и ссылок в Python. Мы изучили, как Python обрабатывает присвоения, как создавать ссылки и как работать с изменяемыми и неизменяемыми объектами. Разбирая эти концепции, вы будете в лучшем состоянии для написания эффективного и правильного кода на Python.