← Назад к вопросам

Можно ли влиять на типизацию в Python?

1.7 Middle🔥 151 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Можно ли влиять на типизацию в Python

Да, можно влиять на типизацию в Python несколькими способами. Python — динамически типизированный язык, но поддерживает type hints и различные механизмы для проверки и манипулирования типами.

1. Type Hints (Аннотации типов)

Type hints позволяют указывать ожидаемые типы, но они не проверяются в runtime по умолчанию:

def add(a: int, b: int) -> int:
    return a + b

def process(data: tuple[int, str]) -> None:
    pass

def get_items() -> list[str]:
    return ["a", "b", "c"]

def config() -> dict[str, int]:
    return {"timeout": 30}

from typing import Optional
def find_user(user_id: int) -> Optional[str]:
    return None

2. Проверка типов в Runtime с Pydantic

Pydantic автоматически проверяет типы при создании объектов:

from pydantic import BaseModel, field_validator

class User(BaseModel):
    id: int
    name: str
    email: str
    age: int
    
    @field_validator('age')
    @classmethod
    def validate_age(cls, v):
        if v < 0 or v > 150:
            raise ValueError('Invalid age')
        return v

user = User(id=1, name="John", email="john@example.com", age=30)

3. Проверка типов с isinstance()

x = 42
print(type(x))  # <class 'int'>
print(isinstance(x, int))  # True

def process(data):
    if isinstance(data, int):
        return data * 2
    elif isinstance(data, str):
        return data.upper()
    else:
        raise TypeError(f"Unsupported type: {type(data)}")

print(process(10))  # 20
print(process("hello"))  # HELLO

4. Использование Protocols

from typing import Protocol, runtime_checkable

@runtime_checkable
class Drawable(Protocol):
    def draw(self) -> None: ...

class Circle:
    def draw(self) -> None:
        print("Drawing circle")

def render(obj):
    if isinstance(obj, Drawable):
        obj.draw()
    else:
        raise TypeError(f"{type(obj)} is not Drawable")

render(Circle())  # OK

5. Union типы для нескольких вариантов

from typing import Union

def process(data: Union[int, str, float]) -> None:
    if isinstance(data, int):
        print(f"Integer: {data}")
    elif isinstance(data, str):
        print(f"String: {data}")
    else:
        print(f"Float: {data}")

# Modern syntax (Python 3.10+)
def process_v2(data: int | str | float) -> None:
    pass

6. TypeVar для Generics

from typing import TypeVar, Generic, List

T = TypeVar('T')

class Stack(Generic[T]):
    def __init__(self):
        self.items: List[T] = []
    
    def push(self, item: T) -> None:
        self.items.append(item)
    
    def pop(self) -> T:
        return self.items.pop()

int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
print(int_stack.pop())  # 2

7. Декоратор для проверки типов

from functools import wraps
from typing import get_type_hints

def type_check(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        hints = get_type_hints(func)
        arg_names = list(hints.keys())[:-1]
        
        for arg_name, arg_value in zip(arg_names, args):
            if arg_name in hints:
                expected_type = hints[arg_name]
                if not isinstance(arg_value, expected_type):
                    raise TypeError(
                        f"Argument '{arg_name}' should be {expected_type}"
                    )
        
        return func(*args, **kwargs)
    
    return wrapper

@type_check
def add(a: int, b: int) -> int:
    return a + b

print(add(5, 3))  # OK: 8

8. Использование dataclass

from dataclasses import dataclass
from typing import List

@dataclass
class Book:
    title: str
    author: str
    pages: int
    isbn: str
    
    def __post_init__(self):
        if self.pages <= 0:
            raise ValueError("Pages must be positive")

book = Book(title="Python Guide", author="John", pages=300, isbn="123-456")
print(book)

9. Static Type Checking с mypy

# Файл script.py
def greet(name: str) -> str:
    return f"Hello, {name}"

result: str = greet("Alice")  # OK
result2: int = greet("Bob")  # Error: Incompatible types

# mypy script.py

10. Pydantic для Production

from pydantic import BaseModel, field_validator
from typing import Optional
from fastapi import FastAPI

class CreateUserRequest(BaseModel):
    email: str
    password: str
    name: Optional[str] = None
    age: Optional[int] = None
    
    @field_validator('email')
    @classmethod
    def validate_email(cls, v):
        if '@' not in v:
            raise ValueError('Invalid email')
        return v
    
    @field_validator('password')
    @classmethod
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password too short')
        return v

app = FastAPI()

@app.post("/users")
def create_user(request: CreateUserRequest):
    return {"message": f"User {request.email} created"}

Сравнение подходов

МетодRuntimeStaticПродакшн
Type HintsНетДа (mypy)Да
PydanticДаДаДа
isinstance()ДаНетДа
DecoratorsДаНетИногда
mypyНетДаДа
dataclassЧастичноДаДа

Рекомендации

Для production систем используй:

  • Pydantic для runtime проверки типов
  • Type hints для документации и IDE поддержки
  • mypy для static анализа кода
  • isinstance() для специфичных проверок

Вывод: В Python можно влиять на типизацию через type hints, Pydantic, isinstance() проверки и mypy.

Можно ли влиять на типизацию в Python? | PrepBro