Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Type Identity в Python
Определение
Type Identity — это способность системы типов отличать один тип от другого и гарантировать, что операция работает с правильным типом. В Python это означает:
- id() функция — уникальный идентификатор объекта в памяти
- type() функция — определение типа объекта
- isinstance() функция — проверка принадлежности к типу
- Type Hints — статическая типизация для IDE и mypy
1. id() — Идентичность объекта
Каждый объект в памяти имеет уникальный идентификатор (address in memory):
# id() возвращает адрес объекта в памяти
a = [1, 2, 3]
b = [1, 2, 3]
print(id(a)) # 140320849201344
print(id(b)) # 140320849201412 <- разные объекты!
print(a == b) # True (равное содержимое)
print(a is b) # False (разные объекты)
# Одна переменная = один и тот же объект
c = a
print(id(a)) # 140320849201344
print(id(c)) # 140320849201344
print(a is c) # True (один объект)
2. type() — Определение типа
# type() возвращает класс объекта
print(type(42)) # <class 'int'>
print(type("Hello")) # <class 'str'>
print(type([1, 2, 3])) # <class 'list'>
print(type({"a": 1})) # <class 'dict'>
class User:
pass
user = User()
print(type(user)) # <class '__main__.User'>
# Проверка типа
if type(user) == User:
print("user is User")
3. isinstance() — Проверка типа (ЛУЧШЕ)
# isinstance() лучше type(), потому что работает с наследованием
class Animal:
pass
class Dog(Animal):
pass
dog = Dog()
# ❌ type() не учитывает наследование
print(type(dog) == Animal) # False (неправильно!)
# ✅ isinstance() учитывает наследование
print(isinstance(dog, Dog)) # True
print(isinstance(dog, Animal)) # True (наследник!)
print(isinstance(dog, str)) # False
4. Type Hints — Статическая типизация
Это самая важная часть Type Identity в современном Python:
# ❌ Без типов — IDE не может проверить
def calculate_price(quantity, price):
return quantity * price
# Что если кто-то передаст неправильный тип?
print(calculate_price("5", 10)) # "55555" <- ошибка!
# ✅ С типами — IDE предупредит и mypy поймает ошибку
def calculate_price(quantity: int, price: float) -> float:
return quantity * price
print(calculate_price("5", 10)) # mypy ERROR: Argument 1 has incompatible type "str"; expected "int"
Базовые Type Hints
from typing import List, Dict, Optional, Union, Tuple
# Простые типы
def get_name(user_id: int) -> str:
pass
def is_valid(email: str) -> bool:
pass
# Collections
def process_numbers(numbers: List[int]) -> int:
return sum(numbers)
def get_user(user_id: int) -> Dict[str, str]:
return {"id": str(user_id), "name": "John"}
# Optional (может быть None)
def find_user(user_id: int) -> Optional[str]:
if user_id == 1:
return "John"
return None
# Union (несколько возможных типов)
def parse_value(value: Union[int, str]) -> str:
return str(value)
# Tuple с точными типами
def get_coordinates() -> Tuple[float, float]:
return (40.7128, -74.0060)
Type Hints для классов
from dataclasses import dataclass
from datetime import datetime
from typing import Optional
@dataclass
class User:
id: int
name: str
email: str
created_at: datetime
bio: Optional[str] = None # Может быть None
def update_bio(self, new_bio: str) -> None:
"""Обновляет биографию"""
self.bio = new_bio
def get_full_info(self) -> Dict[str, any]:
return {
"id": self.id,
"name": self.name,
"email": self.email,
"bio": self.bio
}
5. Проверка Type Identity с mypy
mypy — это статический type checker для Python. Проверяет типы БЕЗ выполнения кода:
# file: main.py
def greet(name: str) -> str:
return f"Hello {name}!"
result1 = greet("Ivan") # ✓ OK
result2 = greet(123) # ✗ ERROR: Argument 1 has incompatible type "int"; expected "str"
class DataProcessor:
def process(self, data: List[int]) -> int:
return sum(data)
processor = DataProcessor()
result3 = processor.process([1, 2, 3]) # ✓ OK
result4 = processor.process(["a", "b"]) # ✗ ERROR
# Запуск mypy
mypy main.py
# Результат:
# main.py:8: error: Argument 1 to "greet" has incompatible type "int"; expected "str"
# main.py:18: error: List item 0 has incompatible type "str"; expected "int"
6. Type Guards (проверка типов в runtime)
from typing import Union, TypeGuard
class Dog:
def bark(self):
return "Woof!"
class Cat:
def meow(self):
return "Meow!"
# Type guard функция
def is_dog(animal: Union[Dog, Cat]) -> TypeGuard[Dog]:
return isinstance(animal, Dog)
# Использование
def make_sound(animal: Union[Dog, Cat]) -> str:
if is_dog(animal): # Type guard сказал, что это Dog
return animal.bark() # IDE знает, что у animal есть bark()
else:
return animal.meow()
7. Generic типы (параметризованные типы)
from typing import Generic, TypeVar
T = TypeVar('T') # Тип-переменная
class Container(Generic[T]):
"""Контейнер, который может содержать любой тип T"""
def __init__(self, value: T):
self.value = value
def get(self) -> T:
return self.value
# Использование
int_container: Container[int] = Container(42)
str_container: Container[str] = Container("Hello")
print(int_container.get()) # 42 (type: int)
print(str_container.get()) # "Hello" (type: str)
# mypy будет проверять типы
result: int = int_container.get() # ✓ OK
result2: str = int_container.get() # ✗ ERROR: expected str, got int
8. Protocol — структурная типизация
from typing import Protocol
class Drawable(Protocol):
"""Что-то, что можно нарисовать"""
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("Drawing circle")
class Square:
def draw(self) -> None:
print("Drawing square")
def render(shape: Drawable) -> None:
shape.draw()
# Не нужно наследоваться от Drawable!
# Просто нужно иметь метод draw()
render(Circle()) # ✓ OK (имеет draw)
render(Square()) # ✓ OK (имеет draw)
render(42) # ✗ ERROR (нет draw)
9. Литеральные типы (Literal Types)
from typing import Literal
def set_status(status: Literal["active", "inactive", "pending"]) -> None:
"""Status может быть только одним из этих значений"""
print(f"Status set to {status}")
set_status("active") # ✓ OK
set_status("inactive") # ✓ OK
set_status("deleted") # ✗ ERROR: Literal["active", "inactive", "pending"]
10. Best Practices для Type Identity
# ✅ Правило 1: Всегда типизируйте публичные функции
def fetch_user(user_id: int) -> Optional[Dict[str, any]]:
pass
# ✅ Правило 2: Используйте isinstance, не type
if isinstance(value, str):
pass
# ✅ Правило 3: Используйте dataclass для структур данных
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
email: str
# ✅ Правило 4: Запускайте mypy в CI/CD
# в Makefile или pre-commit hook
run_mypy:
mypy app/ --strict
# ✅ Правило 5: Используйте Union для нескольких типов
def process(value: Union[int, str]) -> str:
return str(value)
# ❌ Правило 6: НЕ используйте any
def bad_function(value: any):
pass # Теряется смысл типизации
Итог
Type Identity — это система, которая гарантирует, что код работает с правильными типами:
- id() — адрес объекта в памяти
- type() — получить тип объекта
- isinstance() — проверить тип (учитывает наследование)
- Type Hints — статическая типизация (для IDE и mypy)
- mypy — проверка типов без выполнения кода
Модерный Python требует типизации. Это не обязательно, но это:
- Делает код понятнее
- Предотвращает ошибки
- Помогает IDE давать лучшие подсказки
- Улучшает поддерживаемость
Если код без типов — это как вождение без фар ночью. Технически возможно, но очень опасно.