Значения в Python: присваивание, ссылки, копирование и структуры данных
Основы хранения значений в Python
В Python каждое значение (число, строка, список, экземпляр класса) является объектом. Переменная - это всего лишь имя, которое ссылается на объект в памяти. Наиболее эффективное и прямое решение для хранения значения - присвоить его переменной:
x = 42
print(x) # 42Python arguments types (типы аргументов в python)
При этом Python не копирует значение, а создаёт ссылку. Для неизменяемых типов (int, str, tuple) это не вызывает побочных эффектов, но для изменяемых (list, dict) требуется осознанное управление копированием.
Различные способы хранения значений
Как сохранить одно значение и при этом гарантировать его неизменность?
Используйте переменную с неизменяемым типом. Например:
CONST = 3.14159Python load module (загрузка модуля в python)
Если требуется запретить переприсваивание, используйте typing.Final (только для статического анализа) или константы на уровне модуля.
Типичная ошибка: попытка изменить значение через объект, который кажется неизменяемым, но содержит изменяемые элементы (кортеж со списком). Решение - заменить кортеж на неизменяемое представление, например, на tuple из неизменяемых объектов.
Как хранить несколько однотипных значений, поддерживающих изменение?
Список (list) идеально подходит для динамического набора элементов:
numbers = [1, 2, 3]
numbers.append(4)
print(numbers) # [1, 2, 3, 4]
Pd pandas python (импорт пакетов python)
Для фиксированного набора используйте кортеж (tuple), который нельзя изменить после создания.
Проблема: присваивание списка другой переменной не копирует данные, а создаёт новую ссылку. Изменение через одну переменную затрагивает другую. Решение - явное копирование: new_list = original_list.copy() или list(original_list).
Как хранить пары «ключ-значение» для быстрого доступа?
Словарь (dict) обеспечивает доступ по уникальному ключу:
user = {'name': 'Анна', 'age': 30}
print(user['name']) # АннаHow to use python (как использовать python)
Для упорядоченного словаря (Python 3.7+) порядок вставки сохраняется.
Ошибка: попытка обращения к несуществующему ключу вызывает KeyError. Решение - метод get(key, default) или условие if key in dict.
Как хранить только уникальные значения?
Множество (set) автоматически удаляет дубликаты:
tags = {'python', 'programming', 'python'}
print(tags) # {'python', 'programming'}как писать код на python (как писать код на python)
Элементы множества должны быть неизменяемыми (числа, строки, кортежи).
Подводный камень: множество не поддерживает индексацию. Для доступа к элементу нужно преобразовать в список или использовать цикл.
Глубокое и поверхностное копирование
Как скопировать сложный объект, не затрагивая исходный?
Модуль copy предоставляет две функции: copy.copy (поверхностное копирование) и copy.deepcopy (рекурсивное копирование всех вложенных объектов).
import copy
original = {'a': [1, 2], 'b': 3}
shallow = copy.copy(original)
deep = copy.deepcopy(original)
original['a'].append(3)
print(shallow['a']) # [1, 2, 3] - изменилось
print(deep['a']) # [1, 2] - не изменилосьPython log 2 (логарифм по основанию 2 в python)
Предостережение: глубокое копирование может быть медленным для больших структур и не работает с объектами, содержащими ссылки на внешние ресурсы (файлы, сокеты). В таких случаях лучше реализовать собственный метод копирования.
Хранение значений в именованных структурах
Как создать простую структуру с именованными полями без написания целого класса?
Используйте namedtuple из модуля collections или dataclasses:
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y) # 10 20
from dataclasses import dataclass
@dataclass
class Person:
name: str
age: int
person = Person('Иван', 25)
print(person) # Person(name='Иван', age=25)
Ограничение: namedtuple является неизменяемым (поля нельзя изменить после создания). dataclass по умолчанию изменяем, что может привести к неожиданным изменениям, если объект используется как ключ словаря. Решение - указать frozen=True.
Расширенные примеры хранения значений
Пример 1: Копирование с пониманием ссылочной модели
a = [1, 2, [3, 4]]
b = a # ссылка
c = a.copy() # поверхностная копия
d = a[:] # тоже поверхностная
import copy
e = copy.deepcopy(a)
a[2].append(5)
print(a) # [1, 2, [3, 4, 5]]
print(b) # [1, 2, [3, 4, 5]]
print(c) # [1, 2, [3, 4, 5]] - вложенный список общий
print(d) # [1, 2, [3, 4, 5]]
print(e) # [1, 2, [3, 4]] - глубокое копирование избегает изменений
Вывод показывает, что только e остаётся неизменным.
Пример 2: Хранение функций в словаре (стратегия выбора)
def add(x, y): return x + y
def sub(x, y): return x - y
operations = {
'+': add,
'-': sub
}
print(operations['+'](5, 3)) # 8
8
Это полезно для реализации командных диспетчеров или конечных автоматов.
Пример 3: Хранение значений с помощью замыканий
def make_counter(start):
count = start
def counter():
nonlocal count
count += 1
return count
return counter
c1 = make_counter(0)
print(c1()) # 1
print(c1()) # 2
1 2
Замыкание сохраняет состояние между вызовами без глобальных переменных.
Пример 4: Использование __slots__ для экономии памяти
class Point:
__slots__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
# p.z = 3 # AttributeError
__slots__ запрещает создание словаря экземпляра, уменьшая потребление памяти. Поля становятся фиксированными.
Пример 5: Хранение данных в сериализованном виде (JSON)
import json
data = {'name': 'База данных', 'values': [1, 2, 3]}
with open('data.json', 'w') as f:
json.dump(data, f)
with open('data.json', 'r') as f:
restored = json.load(f)
print(restored) # {'name': 'База данных', 'values': [1, 2, 3]}
{'name': 'База данных', 'values': [1, 2, 3]}
Подходит для долговременного хранения и обмена между программами.