Привет! В Python вы могли заметить, что переменная сначала хранит число, потом строку, потом список. Это не баг — это фича. Python использует динамическую типизацию.
В этой статье мы разберём:
- Что такое динамическая типизация
- Как она работает в Python
- Её плюсы и минусы
- Сравнение со статической типизацией
- Когда использовать аннотации типов
- Что нужно знать перед началом
- Основная часть
- Что такое динамическая типизация
- Как это работает под капотом
- Плюсы динамической типизации
- 1. Скорость разработки
- 2. Гибкость
- 3. Меньше кода
- 4. Простота прототипирования
- Минусы динамической типизации
- 1. Ошибки во время выполнения
- 2. Сложность отладки
- 3. Производительность
- 4. Меньшая самодокументированность
- Статическая vs динамическая типизация
- Аннотации типов (Type Hints)
- Инструменты для статической проверки типов
- Утиная типизация (Duck Typing)
- Задачи для закрепления
- Нюансы и подводные камни
- Приведение типов при операции
- Изменение типа внутри функции
- Неявное приведение bool и int
- Частые ошибки и как их избежать
- Ошибка 1: Неправильный тип в функции
- Ошибка 2: Изменение типа переменной случайно
- Ошибка 3: Игнорирование None
- Шпаргалка
- КВИЗ
- Заключение / Выводы
- Что дальше?
Что нужно знать перед началом
Для этого урока тебе понадобится:
- Установленный Python
- Базовое понимание переменных и типов данных (статьи 2–8)
Совет: Понимание типизации поможет тебе писать более осознанный код и выбирать правильные инструменты для задач.
Основная часть
Что такое динамическая типизация
Динамическая типизация — это подход, при котором тип переменной определяется во время выполнения программы, а не в момент написания кода.
Переменная в Python — это просто «имя», которое ссылается на объект. Тип хранится у объекта, а не у переменной.
x = 10 # x ссылается на int
print(type(x)) # <class 'int'>
x = "hello" # x теперь ссылается на str
print(type(x)) # <class 'str'>
x = [1, 2, 3] # x теперь ссылается на list
print(type(x)) # <class 'list'>Важно: В Python переменная не имеет фиксированного типа. Она просто «указывает» на объект, а объект уже знает, кто он.
Как это работает под капотом
В статически типизированных языках (Java, C++) вы объявляете тип переменной заранее:
// Java
int x = 10; // x всегда будет int
x = "hello"; // Ошибка! Нельзя присвоить строку intВ Python всё иначе:
# Python
x = 10 # Можно
x = "hello" # Можно! Переменная просто меняет объектЭто делает код гибким, но требует внимательности.
Плюсы динамической типизации
1. Скорость разработки
Не нужно объявлять типы, писать конструкторы, касты. Код пишется быстрее.
# Написать функцию для обработки любого типа
def print_info(data):
print(f"Тип: {type(data).__name__}, значение: {data}")
print_info(42) # Тип: int, значение: 42
print_info("hello") # Тип: str, значение: hello
print_info([1, 2, 3]) # Тип: list, значение: [1, 2, 3]2. Гибкость
Одна и та же функция может работать с разными типами данных (полиморфизм).
def double(data):
return data * 2
print(double(5)) # 10
print(double("ha")) # haha
print(double([1, 2])) # [1, 2, 1, 2]3. Меньше кода
Не нужно писать перегрузки функций для разных типов.
4. Простота прототипирования
На ранних этапах разработки можно быстро менять структуры данных.
Минусы динамической типизации
1. Ошибки во время выполнения
Ошибки, связанные с типами, обнаруживаются только при запуске программы.
def add(a, b):
return a + b
print(add(5, 10)) # 15
print(add(5, "hello")) # TypeError: unsupported operand type(s) for +: 'int' and 'str'В статически типизированных языках такая ошибка будет найдена на этапе компиляции.
2. Сложность отладки
Если переменная меняет тип в процессе выполнения, бывает трудно понять, где и почему это произошло.
3. Производительность
Python должен проверять типы во время выполнения, что немного замедляет работу.
4. Меньшая самодокументированность
Без явного указания типа сложнее понять, что ожидает функция.
def process(data): # Что должно быть в data? Строка? Число? Список?
# ...Статическая vs динамическая типизация
| Характеристика | Статическая (Java, C++) | Динамическая (Python) |
|---|---|---|
| Проверка типов | На этапе компиляции | Во время выполнения |
| Гибкость | Низкая | Высокая |
| Скорость разработки | Медленнее | Быстрее |
| Производительность | Выше | Ниже |
| Ошибки типов | Находятся рано | Находятся поздно |
| Самодокументированность | Высокая | Низкая |
Аннотации типов (Type Hints)
Python позволяет добавлять подсказки о типах (аннотации), но они не проверяются интерпретатором.
def greet(name: str) -> str:
return f"Привет, {name}!"
def add(a: int, b: int) -> int:
return a + bЧто дают аннотации?
- Помогают IDE (VS Code, PyCharm) давать подсказки
- Делают код более понятным для разработчиков
- Могут использоваться сторонними инструментами (mypy) для проверки типов
Совет: Используй аннотации типов в серьёзных проектах. Это улучшает читаемость и помогает отлавливать ошибки.
Инструменты для статической проверки типов
Хотя Python динамически типизирован, есть инструменты, которые позволяют проверить типы статически.
mypy — самый популярный инструмент для проверки аннотаций типов.
# Установка
pip install mypy
# Проверка файла
mypy script.py
# Пример ошибки, которую найдёт mypy
def add(a: int, b: int) -> int:
return a + b
result = add(5, "hello") # mypy укажет на ошибку типаСовет: В крупных проектах настрой mypy как часть CI/CD процесса.
Утиная типизация (Duck Typing)
Python использует утиную типизацию: «Если это плавает как утка и крякает как утка, значит это утка».
Вместо проверки типа, Python проверяет наличие методов.
def make_sound(animal):
animal.sound() # Если у объекта есть метод sound() — он подойдёт
class Dog:
def sound(self):
print("Гав!")
class Cat:
def sound(self):
print("Мяу!")
make_sound(Dog()) # Гав!
make_sound(Cat()) # Мяу!Совет: В Python важнее поведение, а не тип. Сосредоточься на том, что объект может делать, а не на том, кем он является.
Задачи для закрепления
Попробуй решить задачи самостоятельно.
Задача 1. Что выведет код?
x = 10
x = "hello"
x = [1, 2, 3]
print(type(x))Задача 2. Какая ошибка возникнет при выполнении?
def concat(a, b):
return a + b
print(concat(5, 10))
print(concat(5, "10"))Задача 3. Что такое динамическая типизация?
Задача 4. Как аннотировать функцию, которая принимает строку и число и возвращает строку?
Задача 5. Почему ошибки типов в Python обнаруживаются позже, чем в Java?
Ответы
Задача 1
# <class 'list'>
# x сначала ссылался на int, потом на str, потом на list.
# В конце тип — list.Задача 2
# concat(5, 10) -> 15
# concat(5, "10") -> TypeError: unsupported operand type(s) for +: 'int' and 'str'Задача 3
# Динамическая типизация — это подход, при котором тип переменной
# определяется во время выполнения программы, а не в момент написания кода.Задача 4
def format_message(name: str, age: int) -> str:
return f"Привет, {name}! Тебе {age} лет."Задача 5
# Python проверяет типы только в момент выполнения операции (runtime).
# Java проверяет типы на этапе компиляции (compile time),
# поэтому ошибки типов обнаруживаются раньше.Нюансы и подводные камни
Приведение типов при операции
print(5 + 10) # 15 (int)
print("5" + "10") # "510" (str)
print(5 + "10") # TypeError — нельзя!Совет: Всегда явно приводи типы, если сомневаешься.
Изменение типа внутри функции
def process(data):
data = data + 5 # Если data — строка — ошибка
# ...Неявное приведение bool и int
print(True + 5) # 6 (True == 1)
print(False * 3) # 0 (False == 0)Частые ошибки и как их избежать
Ошибка 1: Неправильный тип в функции
def double(x):
return x * 2
double(5) # 10
double("ha") # "haha"
double([1,2]) # [1,2,1,2]Как избежать: Используй аннотации типов и проверяй ожидаемый тип.
Ошибка 2: Изменение типа переменной случайно
x = 10
x = x + 5.0 # x стал float
print(type(x)) # <class 'float'>Как избежать: Явно приводи типы или используй аннотации.
Ошибка 3: Игнорирование None
def get_value():
return None
value = get_value()
print(value * 2) # TypeError: unsupported operand type(s) for *: 'NoneType' and 'int'Как избежать: Проверяй переменные на None перед операциями.
Шпаргалка
| Что нужно | Как пишется |
|---|---|
| Проверить тип | type(x) |
| Проверить, является ли x int | isinstance(x, int) |
| Аннотация типа для переменной | x: int = 10 |
| Аннотация для функции | def add(a: int, b: int) -> int: |
| Утиная типизация | Проверка наличия метода |
| Статический анализатор | mypy script.py |
КВИЗ
Заключение / Выводы
Сегодня мы узнали:
- Динамическая типизация — тип переменной определяется во время выполнения
- Плюсы: скорость разработки, гибкость, меньше кода
- Минусы: ошибки во время выполнения, сложнее отладка, медленнее
- Аннотации типов — помогают улучшить читаемость и использовать
mypy - Утиная типизация — важнее поведение, а не тип








