Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Зачем нужна интроспекция
Интроспекция (Introspection) — это способность программы исследовать самоё себя во время выполнения: узнавать о типах объектов, их атрибутах, методах и других свойствах. Python — один из самых интроспективных языков, что делает его удобным для разработки.
Основные инструменты интроспекции
1. type() — определить тип объекта
type(5) # <class 'int'>
type("hello") # <class 'str'>
type([1, 2, 3]) # <class 'list'>
type({"key": "value"}) # <class 'dict'>
class MyClass:
pass
obj = MyClass()
type(obj) # <class '__main__.MyClass'>
2. isinstance() — проверить является ли объект экземпляром класса
isinstance(5, int) # True
isinstance("hello", str) # True
isinstance(5, (int, float)) # True — проверка нескольких типов
isinstance([1, 2], list) # True
# Со своими классами
class Animal:
pass
class Dog(Animal):
pass
dog = Dog()
isinstance(dog, Dog) # True
isinstance(dog, Animal) # True — работает с наследованием
3. dir() — список всех атрибутов и методов
dir("hello")
# ['__add__', '__class__', '__contains__', ..., 'capitalize', 'casefold', ..., 'upper', 'zfill']
dir([1, 2, 3])
# ['__add__', '__class__', ..., 'append', 'clear', 'copy', 'count', 'extend', ..., 'sort']
class MyClass:
def method1(self):
pass
def method2(self):
pass
obj = MyClass()
dir(obj)
# [..., 'method1', 'method2']
4. getattr() / setattr() / hasattr() — работа с атрибутами
class Person:
name = "John"
age = 30
obj = Person()
# getattr — получить значение атрибута
getattr(obj, 'name') # "John"
getattr(obj, 'email', 'unknown') # 'unknown' — значение по умолчанию
# hasattr — проверить наличие атрибута
hasattr(obj, 'name') # True
hasattr(obj, 'email') # False
# setattr — установить атрибут
setattr(obj, 'name', 'Jane')
obj.name # "Jane"
# delattr — удалить атрибут
delattr(obj, 'name')
hasattr(obj, 'name') # False
5. callable() — проверить является ли объект вызываемым
def my_function():
pass
callable(my_function) # True
callable(lambda x: x) # True
class MyClass:
def __call__(self):
return "Called"
obj = MyClass()
callable(obj) # True
callable(5) # False
callable("string") # False
6. inspect модуль — глубокий анализ
import inspect
def my_function(a, b, c=10):
"""Описание функции"""
return a + b + c
# Получить сигнатуру функции
sig = inspect.signature(my_function)
print(sig) # (a, b, c=10)
# Получить параметры
for param_name, param in sig.parameters.items():
print(f"{param_name}: {param.default}") # a: <class 'inspect._empty'>
# b: <class 'inspect._empty'>
# c: 10
# Получить исходный код
print(inspect.getsource(my_function))
# def my_function(a, b, c=10):
# return a + b + c
# Получить информацию о классе
class MyClass:
def method1(self):
pass
def method2(self):
pass
for name, method in inspect.getmembers(MyClass, predicate=inspect.ismethod):
print(name) # method1, method2
Практические примеры использования
1. Динамическое создание объектов
# Создание объекта по его имени (строка)
class Dog:
def bark(self):
return "Woof!"
class Cat:
def meow(self):
return "Meow!"
def create_animal(animal_name):
"""Создать животное по названию"""
# Получить класс по имени
animal_class = globals()[animal_name] # Интроспекция!
return animal_class()
dog = create_animal('Dog')
print(dog.bark()) # Woof!
cat = create_animal('Cat')
print(cat.meow()) # Meow!
2. Автоматическая валидация данных
import inspect
from typing import get_type_hints
class User:
name: str
age: int
email: str
def validate(obj, data):
"""Валидировать данные по типам класса"""
hints = get_type_hints(obj.__class__)
for field, field_type in hints.items():
if field in data:
if not isinstance(data[field], field_type):
raise TypeError(f"{field} must be {field_type.__name__}")
setattr(obj, field, data[field])
user = User()
validate(user, {'name': 'John', 'age': 30, 'email': 'john@example.com'})
print(user.name) # John
print(user.age) # 30
# Неверный тип выбросит исключение
# validate(user, {'age': 'thirty'}) # TypeError
3. Сериализация объектов
import json
from dataclasses import asdict, dataclass
@dataclass
class Person:
name: str
age: int
city: str
person = Person("Alice", 30, "New York")
# Сериализация через интроспекцию
json_str = json.dumps(asdict(person))
print(json_str) # {"name": "Alice", "age": 30, "city": "New York"}
# Десериализация
data = json.loads(json_str)
person2 = Person(**data)
print(person2.name) # Alice
4. Декоратор для логирования всех методов
import functools
import inspect
def log_all_methods(cls):
"""Автоматически добавить логирование ко всем методам"""
for name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
if not name.startswith('_'):
original = method
@functools.wraps(original)
def wrapper(self, *args, **kwargs):
print(f"Calling {name}({args}, {kwargs})")
result = original(self, *args, **kwargs)
print(f"Result: {result}")
return result
setattr(cls, name, wrapper)
return cls
@log_all_methods
class Calculator:
def add(self, a, b):
return a + b
def multiply(self, a, b):
return a * b
calc = Calculator()
calc.add(2, 3) # Логирует вызов и результат
calc.multiply(4, 5) # Логирует вызов и результат
5. Автоматическая генерация API документации
import inspect
class API:
def get_user(self, user_id: int) -> dict:
"""Получить информацию о пользователе"""
return {"id": user_id, "name": "John"}
def create_user(self, name: str, email: str) -> bool:
"""Создать нового пользователя"""
return True
def generate_docs(cls):
"""Автоматически генерировать документацию"""
print(f"API Documentation for {cls.__name__}\n")
for name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
if not name.startswith('_'):
sig = inspect.signature(method)
doc = inspect.getdoc(method)
print(f"- {name}{sig}")
print(f" {doc}\n")
generate_docs(API)
# API Documentation for API
#
# - get_user(user_id: int) -> dict
# Получить информацию о пользователе
#
# - create_user(name: str, email: str) -> bool
# Создать нового пользователя
6. ORM-подобная магия (как Django модели)
class Model:
def __init__(self, **kwargs):
# Интроспекция! Установить все переданные атрибуты
for key, value in kwargs.items():
setattr(self, key, value)
def to_dict(self):
# Получить все атрибуты, исключая методы
result = {}
for name, value in inspect.getmembers(self):
if not name.startswith('_') and not callable(value):
result[name] = value
return result
class User(Model):
pass
user = User(name="Alice", age=30, email="alice@example.com")
print(user.to_dict())
# {'age': 30, 'email': 'alice@example.com', 'name': 'Alice'}
7. Динамическое создание классов
# Создать класс динамически
MyDynamicClass = type('MyDynamicClass', (), {
'x': 10,
'method': lambda self: "Hello from dynamic class"
})
obj = MyDynamicClass()
print(obj.x) # 10
print(obj.method()) # Hello from dynamic class
# Проверить что это реально класс
print(isinstance(obj, MyDynamicClass)) # True
print(type(obj)) # <class 'MyDynamicClass'>
Встроенные функции интроспекции
# id() — уникальный идентификатор объекта
x = [1, 2, 3]
print(id(x)) # 140234567890432
# vars() — словарь атрибутов объекта
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(10, 20)
print(vars(p)) # {'x': 10, 'y': 20}
# repr() и str() — строковое представление
print(repr(5)) # 5
print(repr("hello")) # 'hello'
print(str([1, 2, 3])) # [1, 2, 3]
# help() — встроенная справка
help(len) # Выведет подробную информацию о функции len()
Когда использовать интроспекцию
# ✅ Используйте интроспекцию для:
# - Фреймворков (Django, FastAPI, Flask)
# - Сериализации (JSON, YAML, Protocol Buffers)
# - Тестирования (pytest использует её массово)
# - Валидации данных
# - ORM (SQLAlchemy)
# - API документации (Swagger, OpenAPI)
# - Декораторов и метапрограммирования
# ❌ Избегайте чрезмерной интроспекции:
# - Может понизить производительность
# - Усложняет отладку
# - Сложнее для понимания
Примеры из популярных библиотек
# Django ORM
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField()
# Django использует интроспекцию для:
# - Создания таблиц в БД
# - Валидации данных
# - Генерации админ-панели
# FastAPI
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
# FastAPI использует интроспекцию для:
# - Валидации входных данных
# - Генерации Swagger документации
# - Автоматической сериализации/десериализации
# pytest
import pytest
def test_something():
assert True
# pytest использует интроспекцию для:
# - Поиска тестов (функции начинающиеся с test_)
# - Сбора параметров через @pytest.mark.parametrize
# - Dependency injection через fixtures
Итоги
Интроспекция нужна для:
- Динамического программирования — создание кода во время выполнения
- Фреймворков — автоматизация типичных задач
- Метапрограммирования — изменение поведения кода
- Отладки — понимание структуры объектов
- Тестирования — автоматический поиск и запуск тестов
- Сериализации — преобразование объектов
- Документирования — автоматическая генерация справочников
Интроспекция — это мощный инструмент Python, который делает язык чрезвычайно гибким и выразительным. Все крупные фреймворки используют её интенсивно.