Изменяемые аргументы функций

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

Изменяемые типы

Самые распространенные изменяемые типы — list, dict и set. Вот пример списка:
fruits = ['apple', 'banana', 'cherry']
print(fruits, type(fruits))  # ['apple', 'banana', 'cherry'] <class 'list'>
Со списком list вы можете изменять его элементы, добавлять новые или удалять существующие:
fruits[1] = 'blueberry'       # Меняем 'banana' на 'blueberry'
fruits.append('dragonfruit')  # Добавляем 'dragonfruit' в конец списка
print(fruits)                 # ['apple', 'blueberry', 'cherry', 'dragonfruit']

Неизменяемые типы

С другой стороны, примерами неизменяемых типов являются int, float, string и tuple. После создания вы не можете изменить их содержимое. Вот пример строки string:
message = 'hello'
print(message, type(message))  # hello <class 'str'>
Если попытаться изменить часть строки string, Python не позволит это сделать:
message[0] = 'H'  # Попытка изменить 'h' на 'H' вызовет TypeError
Почему int является неизменяемым? Разве мы не можем изменить значение с помощью += или -=?
Когда мы говорим об изменяемости в Python, мы имеем в виду возможность изменить фактическое значение, хранящееся в памяти. Например, когда у нас есть список, мы можем изменить элемент в списке, и это по-прежнему тот же список в памяти.
Целые числа в Python неизменяемы. Это значит, что значение в памяти изменить нельзя. Если у нас есть число a = 5 и мы выполняем операцию a += 2, может показаться, что мы изменили a. Однако на самом деле Python создал новый объект в памяти со значением 7 и обновил a, чтобы оно указывало на этот новый объект. Исходное значение 5 не было изменено в памяти — поэтому int считаются неизменяемыми.
a = 5
print(id(a))  # Это выводит адрес памяти 'a', допустим, 1001

a += 2
print(a)      # Это выводит 7
print(id(a))  # Теперь выводит другой адрес памяти, допустим, 1002
Функция id в Python возвращает идентификатор объекта, уникальный и постоянный для всего времени его существования. Поэтому, когда мы видим, что идентификатор a изменился после операции a += 2, это явный признак того, что a теперь указывает на новый объект в памяти. Исходное число 5 не было изменено, что подтверждает, что целые числа действительно неизменяемы в Python.

Изменяемые аргументы в функциях

Когда мы передаем изменяемый объект (например, список) в функцию, Python передает в функцию ссылку на этот объект. Это означает, что если функция изменит этот объект, то изменение будет видно и за пределами функции.
Давайте рассмотрим функцию, которая получает список и добавляет в него элемент:
def add_item(my_list):
    my_list.append('added item')  # Добавляем новый элемент в список

shopping_list = ['apples', 'bananas', 'cherries']
print(shopping_list)  # Выводит: ['apples', 'bananas', 'cherries']

# Теперь используем функцию, чтобы добавить элемент в наш список покупок
add_item(shopping_list)
print(shopping_list)  # Выводит: ['apples', 'bananas', 'cherries', 'added item']
Как видите, после вызова функции add_item в нашем списке shopping_list появился новый элемент. Это произошло, даже если мы не изменяли shopping_list напрямую вне функции.
Однако важно понимать, что если внутри функции присвоить новое значение всему изменяемому объекту, это не повлияет на исходный объект. Потому что вы присваиваете локальной переменной функции новую ссылку, не изменяя сам исходный объект. Посмотрим на пример:
def change_list(my_list):
    my_list = ['entirely', 'new', 'list']  # Это не повлияет на исходный список

shopping_list = ['apples', 'bananas', 'cherries']
change_list(shopping_list)
print(shopping_list)  # Все еще выводит: ['apples', 'bananas', 'cherries']
Хотя мы вызвали функцию change_list с аргументом shopping_list, содержимое shopping_list не изменилось. Это потому, что внутри функции my_list получила новую ссылку (на совершенно новый список), в то время как исходная ссылка shopping_list осталась неизменной.
Основной вывод здесь: когда вы передаете изменяемый объект в функцию в Python, помните, что если функция изменяет объект (например, добавляет элемент в список), это изменение будет постоянным и будет видно вне функции. Но если вы присваиваете новое значение всему объекту внутри функции, это не повлияет на исходный объект.
 
To check your solution you need to sign in
Sign in to continue