← Назад к вопросам
Как еще называются неизменяемые типы данных в Python?
1.6 Junior🔥 81 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как еще называются неизменяемые типы данных в Python?
Неизменяемые типы данных в Python называются Immutable Types или Hashable Types. На русском: неизменяемые типы или хешируемые типы.
Определение
Неизменяемый тип (Immutable Type) — это тип данных, значение которого не может быть изменено после создания. Любая попытка изменить вызывает ошибку или создаёт новый объект.
Основные неизменяемые типы в Python
# 1. Числа (int, float, complex)
x = 42
x = 43 # На самом деле создаётся НОВЫЙ объект
print(id(x)) # каждый раз новый id
# 2. Строки (str)
text = "Hello"
text[0] = "J" # TypeError: 'str' object does not support item assignment
text = "Hello" + " World" # создаёт новую строку
# 3. Кортежи (tuple)
t = (1, 2, 3)
t[0] = 10 # TypeError: 'tuple' object does not support item assignment
# 4. Frozen sets (frozenset)
fs = frozenset([1, 2, 3])
# fs.add(4) # AttributeError
# 5. Bytes
b = b"hello"
# b[0] = 65 # TypeError
# 6. None
# None всегда одно и то же значение
Изменяемые типы (для сравнения)
# 1. Списки (list) — изменяемые
lst = [1, 2, 3]
lst[0] = 10 # Изменяем в месте
print(lst) # [10, 2, 3]
# 2. Словари (dict) — изменяемые
d = {"a": 1, "b": 2}
d["a"] = 10 # Изменяем в месте
# 3. Множества (set) — изменяемые
s = {1, 2, 3}
s.add(4) # Добавляем в месте
Чем отличаются: изменяемые vs неизменяемые
# НЕИЗМЕНЯЕМАЯ (str)
s1 = "hello"
s2 = s1
s1 = "world" # создаёт новый объект
print(s2) # "hello" — не повлияло!
# ИЗМЕНЯЕМАЯ (list)
lst1 = [1, 2, 3]
lst2 = lst1
lst1[0] = 99 # изменяет в месте
print(lst2) # [99, 2, 3] — повлияло!
Это важно при работе с функциями:
def modify_immutable(s: str):
s = s + " modified"
return s
text = "hello"
result = modify_immutable(text)
print(text) # "hello" — не изменилась
print(result) # "hello modified"
def modify_mutable(lst: list):
lst[0] = 999
return lst
original = [1, 2, 3]
result = modify_mutable(original)
print(original) # [999, 2, 3] — изменилась!
print(result) # [999, 2, 3]
Hashable vs Non-Hashable
Hashable (хешируемые) — это объекты, которые можно использовать как ключи словаря или элементы множества. Обычно это синоним неизменяемых типов.
# Hashable (работает как ключ dict или элемент set)
dict_keys = {
1: "int",
"name": "str",
(1, 2): "tuple",
frozenset([1, 2]): "frozenset"
}
my_set = {1, "text", (1, 2), frozenset([3, 4])}
# Non-hashable (ошибка как ключ dict)
dict_bad = {
[1, 2]: "list" # TypeError: unhashable type: 'list'
}
my_set_bad = {1, "text", [1, 2]} # TypeError: unhashable type: 'list'
Как проверить, hashable ли объект?
from collections.abc import Hashable
print(isinstance("hello", Hashable)) # True
print(isinstance((1, 2), Hashable)) # True
print(isinstance([1, 2], Hashable)) # False
print(isinstance({1, 2}, Hashable)) # False
# Или вызвать hash()
print(hash("hello")) # 5233100571393351674
print(hash((1, 2))) # 529344067295497451
print(hash([1, 2])) # TypeError: unhashable type: 'list'
Особенный случай: tuple с изменяемыми элементами
# Tuple с неизменяемыми элементами — hashable
t1 = (1, "text", (2, 3))
print(hash(t1)) # работает
print({t1}) # можно в set
# Tuple с изменяемыми элементами — NOT hashable!
t2 = (1, "text", [2, 3]) # содержит list
print(hash(t2)) # TypeError: unhashable type: 'list'
print({t2}) # TypeError
Почему это важно?
# 1. Безопасность в многопоточности
import threading
immutable_string = "config_value"
# Две ниточки могут читать одновременно, не боясь конфликтов
mutable_list = [1, 2, 3]
# Две ниточки могут сломать друг другу данные!
# 2. Кеширование
from functools import lru_cache
@lru_cache(maxsize=128)
def expensive_function(items: tuple) -> int:
# Работает! tuple hashable
return sum(items)
# expensive_function([1, 2, 3]) # TypeError!
# 3. Словари и множества
user_cache = {}
# Ключи должны быть hashable
user_cache[(user_id, timestamp)] = data # tuple — OK
user_cache[[user_id, timestamp]] = data # list — ERROR
# 4. Копирование vs изменение
import copy
original = (1, 2, [3, 4])
shallow = copy.copy(original)
shallow[2][0] = 999 # изменили список внутри
print(original) # (1, 2, [999, 4]) — повлияло!
deep = copy.deepcopy(original)
deep[2][0] = 999 # не повлияет на оригинал
Performance: неизменяемые быстрее
import timeit
# Создание строки (неизменяемая)
print(timeit.timeit('x = "hello"', number=1000000))
# Создание списка (изменяемая)
print(timeit.timeit('x = ["hello"]', number=1000000))
# Список медленнее из-за дополнительного управления памятью
# Поиск в неизменяемом (хеш-таблица)
print(timeit.timeit('"hello" in ("hello", "world", "test")', number=1000000))
# Поиск в изменяемом (линейный поиск)
print(timeit.timeit('["hello"] in [["hello"], ["world"], ["test"]]', number=1000000))
Best Practices
# 1. Используй неизменяемые типы по умолчанию
def config():
return { # dictionary
"database": ("localhost", 5432), # tuple для хоста/порта
"allowed_hosts": frozenset(["localhost", "127.0.0.1"]) # frozenset
}
# 2. Передавай tuple вместо list в функции
def process_numbers(*numbers: int) -> int: # *args даёт tuple
return sum(numbers)
# 3. Используй frozen dataclasses для конфигов
from dataclasses import dataclass
@dataclass(frozen=True)
class Config:
debug: bool
db_url: str
max_connections: int
config = Config(debug=False, db_url="postgres://", max_connections=10)
# config.debug = True # FrozenInstanceError
# 4. Используй NamedTuple для структурированных данных
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
p = Point(10, 20)
print(hash(p)) # hashable!
my_dict = {p: "origin"} # можно ключом
Резюме
| Термин | Значение |
|---|---|
| Immutable | Не может быть изменена после создания |
| Hashable | Может быть ключом словаря или элементом множества |
| Неизменяемые типы | str, int, float, tuple, frozenset, bytes, None |
| Изменяемые типы | list, dict, set |
В Python неизменяемость и хешируемость идут рука об руку. Неизменяемые объекты безопаснее для многопоточности и быстрее для кеширования.