Встроенный модуль builtins и типизация в Python
Встроенный модуль builtins и типизация в Python
Что такое модуль builtins
Модуль builtins — это системный компонент стандартной библиотеки языка программирования Python, содержащий определения всех глобально доступных объектов. Эти объекты становятся доступными в каждой новой программе без необходимости явного импорта. К ним относятся встроенные функции, классы типов данных, исключения и специальные переменные.
В контексте статического анализа типов файл builtins.pyi служит справочником для инструментов проверки типов, таких как mypy, pyright или редакторы кода (IDE). Этот файл не содержит исполняемого кода. Он описывает сигнатуры функций, типы аргументов, возвращаемые значения и атрибуты классов. Реальная логика работы этих объектов реализована на языке C внутри интерпретатора Python.
Файл стубов (builtins.pyi) находится в репозитории typeshed. Это официальный проект сообщества Python, поддерживающий набор файлов с объявлениями типов для стандартной библиотеки и внешних пакетов. Синхронизация версий критична: использование устаревшего набора typeshed с современной версией Python может привести к ошибкам валидации типов или пропуску новых возможностей языка.
Глобально доступный объект
Глобально доступный объект — это сущность в языке программирования Python, которая автоматически импортируется в пространство имен каждого нового скрипта или модуля при их загрузке. Эти объекты не требуют явного вызова инструкции import для своего использования. Они доступны в любом месте кода с момента начала выполнения программы.
Все глобально доступные объекты определены внутри встроенного модуля builtins. Этот модуль содержит реализации базовых типов данных, функций ввода-вывода, исключений и специальных переменных. Интерпретатор Python загружает содержимое этого модуля в глобальную область видимости перед выполнением пользовательского кода.
Примеры глобально доступных объектов:
- Типы данных:
int,str,list,dict,tuple,set,bool,float,bytes,NoneType. - Функции:
print,input,len,type,range,open,sorted,map,filter. - Исключения:
Exception,ValueError,TypeError,KeyError,IndexError. - Специальные константы:
__debug__.
Эти объекты являются фундаментом языка. Их реализация выполнена на уровне интерпретатора (чаще всего на языке C), что обеспечивает высокую скорость работы и минимальные накладные расходы.
Рассмотрим практическое применение функции len(), которая является глобально доступной. Эта функция возвращает количество элементов в контейнере (строке, списке, словаре и т.д.).
data_list = [10, 20, 30, 40, 50]
text_string = "Hello World"
user_dict = {"name": "Timur", "age": 31}
count_items = len(data_list)
count_chars = len(text_string)
count_keys = len(user_dict)
print(f"Количество элементов в списке: {count_items}")
print(f"Количество символов в строке: {count_chars}")
print(f"Количество ключей в словаре: {count_keys}")
В данном примере:
data_list— список целых чисел;text_string— строка символов;user_dict— словарь с парами ключ-значение;len()— функция, вызываемая без импорта, так как она доступна глобально;print()— функция вывода результата на экран.
Анализатор типов (например, mypy) использует информацию из файла стубов builtins.pyi, чтобы понять, что функция len() принимает аргумент типа Sized и возвращает значение типа int. Если передать в функцию аргумент неподдерживаемого типа, статический анализатор выдаст ошибку до запуска программы.
Стуб
Стуб (stub file) — это файл декларации типов с расширением .pyi, который описывает сигнатуры функций, классы, переменные и их типы, но не содержит исполняемого кода. Файлы стубов используются системами статического анализа типов (такими как mypy, pyright, IDE) для проверки корректности кода без его выполнения.
В контексте модуля builtins существует специальный файл builtins.pyi, расположенный в репозитории typeshed. Этот файл содержит полные описания всех глобально доступных объектов Python.
Основные характеристики файлов стубов:
- Отсутствие логики: Внутри файла нет операторов присваивания, циклов или условий. Только объявления типов.
- Синтаксис PEP 484 / PEP 604: Используются аннотации типов, обобщения (Generics), Union-типы.
- Поддержка версий: Репозиторий typeshed поддерживает разные версии Python. Для Python 3.10+ файл
builtins.pyiбудет содержать описание новых возможностей, таких как оператор|для объединения типов. - Источник истины: Студенты и разработчики не редактируют этот файл вручную. Обновления вносятся сообществом через пулл-реквесты в официальный репозиторий.
Пример фрагмента файла builtins.pyi:
class object(metaclass=object):
def __init__(self) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def print(*objects: object, sep: str = " ", end: str = "\n", file: Optional[TextIO] = None, flush: bool = False) -> None: ...
class int(object):
def __add__(self, other: int) -> int: ...
def __mul__(self, other: int) -> int: ...
Здесь видно, что функция print принимает любое количество объектов (*objects: object), имеет параметры по умолчанию и возвращает None. Класс int определяет методы сложения и умножения, возвращающие тип int.
Как использовать builtins
Модуль builtins можно использовать несколькими способами в зависимости от задачи: получение списка доступных объектов, явный импорт или использование в статическом анализе.
Получение списка объектов
Для просмотра всех глобально доступных объектов в текущей среде выполнения используется функция dir(), передавая ей имя модуля builtins.
import builtins
# Получение списка всех атрибутов модуля builtins
all_objects = dir(builtins)
# Фильтрация только имен, начинающихся с буквы 'p'
print_functions = [obj for obj in all_objects if obj.startswith('p')]
print(f"Найдено функций на 'p': {print_functions}")
# Результат может включать: ['print', 'property']
Явный импорт модуля
Хотя объекты доступны глобально, иногда требуется явно обратиться к модулю, например, чтобы изменить поведение стандартной функции или получить доступ к внутренним атрибутам.
import builtins
# Доступ к исходному имени функции print
original_print = builtins.print
# Переопределение функции print для добавления префикса времени
def custom_print(*args, **kwargs):
original_print("[LOG]", *args, **kwargs)
custom_print("Это сообщение выведено через переопределенную функцию")
Использование в статическом анализе
При работе с инструментами проверки типов (mypy, pyright) файлы стубов используются автоматически. Не нужно подключать builtins.pyi вручную. Достаточно установить сам инструмент и убедиться, что он настроен на использование актуальной версии типов.
# Установка инструмента проверки типов
pip install mypy
# Запуск проверки проекта
mypy your_script.py
Если в коде используется функция, которую не определили в файле стубов, или передан неверный тип аргумента, mypy выдаст предупреждение.
Работа с исключениями
Исключения также являются частью модуля builtins. Их можно перехватывать напрямую, так как они доступны глобально.
try:
value = int("не число")
except ValueError as e:
print(f"Ошибка преобразования: {e}")
except TypeError as e:
print(f"Ошибка типа: {e}")
Здесь ValueError и TypeError — классы исключений, определенные в builtins. Перехват ошибок происходит без импорта этих классов.
Расширение функциональности
Разработчики могут добавлять новые глобальные функции, используя механизм импорта в модуль builtins. Это делается редко, так как может привести к конфликтам имен, но возможно для создания специализированных сред выполнения.
import builtins
def global_math(x, y):
return x + y
builtins.global_math = global_math
# Теперь функцию можно вызвать без импорта
result = global_math(5, 10)
print(result)
В этом примере функция global_math становится доступна глобально после добавления её в пространство имен модуля builtins.
Архитектура и структура содержимого
Структура файла builtins.pyi разделена на несколько логических групп, каждая из которых отвечает за определенный уровень абстракции в языке.
Классы базовых типов
Все встроенные классы наследуются от базового класса object. Они определяют поведение основных структур данных.
| Класс | Описание | Особенности реализации |
|---|---|---|
| object | Базовый класс для всех объектов в Python | Содержат методы __init__, __str__, __repr__, __eq__, __hash__ |
| int | Целое число произвольной длины | Поддерживает арифметику, битовые операции, конвертацию в строку |
| float | Число с плавающей точкой | Двойная точность (64 бита), специализированные методы is_integer() |
| complex | Комплексное число | Хранит действительную и мнимую части |
| bool | Логический тип | Наследуется от int, значения True (1) и False (0) |
| str | Строка символов | Неизменяемый тип, поддерживает Unicode, индексы, срезы |
| bytes | Последовательность байтов | Неизменяемый, используется для бинарных данных |
| bytearray | Изменяемая последовательность байтов | Позволяет модифицировать данные по индексу |
| list | Упорядоченная изменяемая коллекция | Поддерживает добавление, удаление, сортировку, множественные типы |
| tuple | Упорядоченная неизменяемая коллекция | Используется для гомогенных данных, хешируемый при содержании хешируемых элементов |
| dict | Словарь (маппинг ключ-значение) | Неупорядоченный (до Python 3.7), упорядоченный (начиная с 3.7), быстрый поиск по ключу |
| set | Множество уникальных элементов | Неупорядоченный, поддерживает математические операции (объединение, пересечение) |
| frozenset | Неизменяемое множество | Хешируемый аналог set |
| range | Последовательность чисел | Лень-вычисление, генерирует числа по шагу |
| slice | Объект среза | Представляет собой параметры среза [start:stop:step] |
| type | Тип объекта | Метакласс, используемый для создания новых классов |
| NoneType | Тип значения None | Единственный экземпляр — объект None |
Встроенные функции
Сигнатуры функций описывают допустимые аргументы и возвращаемые типы. Ниже приведены основные категории функций с примерами их использования в контексте типизации.
Функции ввода-вывода и обработки
def print(*objects: object, sep: str = " ", end: str = "\n", file: Optional[TextIO] = None, flush: bool = False) -> None: ...
def input(prompt: str = "") -> str: ...
def open(file: Union[str, bytes, os.PathLike], mode: str = "r", buffering: int = -1, encoding: Optional[str] = None, errors: Optional[str] = None, newline: Optional[str] = None, closefd: bool = True, opener: Optional[Callable] = None) -> IO[Any]: ...
- print: Принимает любое количество объектов любого типа. Аргумент
sepразделяет вывод,endзавершает строку. Параметрfileпозволяет перенаправить вывод в поток. - input: Возвращает строку, введенную пользователем. Принимает необязательный параметр приглашения (prompt).
- open: Открывает файл и возвращает объект потока (File-like object). Тип возвращаемого значения зависит от режима открытия и используемой библиотеки.
Функции преобразования и конструирования
def int(x: Union[str, bytes, bytearray], base: int = 10) -> int: ...
def float(x: Union[str, bytes, bytearray]) -> float: ...
def str(object: object = ...) -> str: ...
def list(iterable: Iterable[T] = ...) -> List[T]: ...
def dict(mapping: Mapping[K, V] = ..., **kwargs: Any) -> Dict[K, V]: ...
def tuple(iterable: Iterable[T] = ...) -> Tuple[T, ...]: ...
def set(iterable: Iterable[T] = ...) -> Set[T]: ...
def frozenset(iterable: Iterable[T] = ...) -> FrozenSet[T]: ...
- int: Преобразует строку или число в целое значение. Параметр
baseопределяет систему счисления (по умолчанию 10). - str: Конвертирует любой объект в его строковое представление.
- list/tuple/set/dict/frozenset: Создают коллекции соответствующих типов из итерируемых объектов.
Функции управления потоком и условиями
def len(obj: Sized) -> int: ...
def type(object: object) -> type: ...
def id(object: object) -> int: ...
def hash(object: object) -> int: ...
def issubclass(class_: type, classinfo: Union[type, Tuple[type, ...]]) -> bool: ...
def isinstance(object: object, classinfo: Union[type, Tuple[type, ...]]) -> bool: ...
- len: Возвращает длину контейнера. Работает только с объектами, реализующими протокол
__len__. - type: Возвращает тип указанного объекта.
- id: Возвращает уникальный идентификатор объекта в памяти (целое число).
- hash: Возвращает хеш-значение объекта.
- issubclass: Проверяет, является ли первый аргумент подклассом второго.
- isinstance: Проверяет, является ли объект экземпляром указанного класса или кортежа классов.
Функции итерации и фильтрации
def enumerate(iterable: Iterable[T], start: int = 0) -> Iterator[Tuple[int, T]]: ...
def zip(*iterables: Iterable[T], strict: bool = False) -> Iterator[Tuple[T, ...]]: ...
def reversed(seq: Reversible[T]) -> Iterator[T]: ...
def sorted(iterable: Iterable[T], *, key: Optional[Callable[[T], Any]] = None, reverse: bool = False) -> List[T]: ...
def map(func: Callable[[T], U], iterable: Iterable[T], *iterables: Iterable[T]) -> Iterator[U]: ...
def filter(function: Optional[Callable[[T], bool]], iterable: Iterable[T]) -> Iterator[T]: ...
def range(start: int, stop: Optional[int] = None, step: int = 1) -> range: ...
- enumerate: Добавляет счетчик к элементам итерируемого объекта, возвращая пары (индекс, значение).
- zip: Объединяет элементы нескольких итерируемых объектов в кортежи.
- reversed: Возвращает обратный итератор для последовательности.
- sorted: Возвращает новый отсортированный список. Принимает функции для ключа сортировки и флаг обратного порядка.
- map: Применяет функцию к каждому элементу итерируемого объекта.
- filter: Фильтрует элементы на основе результата применения функции (возвращает
True). - range: Генерирует последовательность целых чисел.
Функции оценки и вызова
def eval(expression: str, globals: Optional[Dict[str, Any]] = None, locals: Optional[Dict[str, Any]] = None) -> Any: ...
def exec(object: Union[bytes, str, code], globals: Optional[Dict[str, Any]] = None, locals: Optional[Dict[str, Any]] = None) -> None: ...
def compile(source: Union[str, bytes], filename: str, mode: str, flags: int = 0, dont_inherit: bool = False, optimize: int = -1) -> code: ...
def callable(object: object) -> bool: ...
- eval: Выполняет строку как выражение Python. Требует осторожности из-за рисков безопасности.
- exec: Выполняет строку как блок кода Python.
- compile: Компилирует исходный код в объект кода для дальнейшего выполнения.
- callable: Проверяет, можно ли вызвать объект как функцию.
Исключения
Все встроенные исключения наследуются от BaseException. Иерархия исключений строго определена в builtins.pyi.
class BaseException(Exception): ...
class Exception(BaseException): ...
class StopIteration(Exception): ...
class GeneratorExit(BaseException): ...
class SystemExit(BaseException): ...
class KeyboardInterrupt(BaseException): ...
class MemoryError(Exception): ...
class ReferenceError(Exception): ...
class RuntimeError(Exception): ...
class NotImplementedError(Exception): ...
class SyntaxError(Exception): ...
class IndentationError(SyntaxError): ...
class TabError(IndentationError): ...
class TypeError(Exception): ...
class ValueError(Exception): ...
class ZeroDivisionError(ValueError): ...
class OverflowError(ValueError): ...
class FloatingPointError(ValueError): ...
class LookupError(Exception): ...
class IndexError(LookupError): ...
class KeyError(LookupError): ...
class AttributeError(AttributeError): ...
class NameError(NameError): ...
class UnboundLocalError(NameError): ...
class ImportError(ImportError): ...
class ModuleNotFoundError(ImportError): ...
class OSError(OSError): ...
class ConnectionError(OSError): ...
class BlockingIOError(OSError): ...
class ChildProcessError(OSError): ...
class BrokenPipeError(OSError): ...
class ConnectionAbortedError(OSError): ...
class ConnectionRefusedError(OSError): ...
class ConnectionResetError(OSError): ...
class FileExistsError(OSError): ...
class FileNotFoundError(OSError): ...
class InterruptedError(OSError): ...
class IsADirectoryError(OSError): ...
class NotADirectoryError(OSError): ...
class PermissionError(OSError): ...
class ProcessLookupError(OSError): ...
class TimeoutError(OSError): ...
class EnvironmentError(OSError): ...
class EOFError(EOFError): ...
class ArithmeticError(ArithmeticError): ...
class BufferError(BufferError): ...
class Warning(Warning): ...
class UserWarning(Warning): ...
class DeprecationWarning(Warning): ...
class PendingDeprecationWarning(Warning): ...
class SyntaxWarning(Warning): ...
class RuntimeWarning(Warning): ...
class FutureWarning(Warning): ...
class ImportWarning(Warning): ...
class UnicodeWarning(Warning): ...
class BytesWarning(Warning): ...
class ResourceWarning(Warning): ...
class EncodingWarning(Warning): ...
Примеры использования исключений в коде:
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Ошибка деления: {e}")
Глобальные переменные и специальные атрибуты
Модуль builtins также содержит некоторые глобальные переменные, доступные в каждом файле.
| Переменная | Тип | Описание |
|---|---|---|
__debug__ | bool | True, если Python запущен без флага -O |
__name__ | str | Имя текущего модуля |
__doc__ | Optional[str] | Документация модуля или объекта |
__package__ | Optional[str] | Имя пакета модуля |
__loader__ | Any | Загрузчик модуля |
__spec__ | Optional[ModuleSpec] | Спецификация модуля |
__build_class__ | Callable | Внутренняя функция для создания классов |
Использование в контексте типизации (PEP 484 / PEP 604)
Статические анализаторы используют информацию из builtins.pyi для проверки корректности кода. Понимание того, как типы определяются в этом файле, помогает правильно использовать аннотации.
Базовая типизация
При объявлении переменных и параметров функций инструменты анализируют возвращаемые типы встроенных функций.
from typing import List, Dict, Optional
def process_data(items: List[int]) -> Dict[str, float]:
total: float = sum(items)
count: int = len(items)
return {"total": total, "count": count}
Здесь sum возвращает int (так как входные данные List[int]), но аннотация float указывает на ожидаемый тип. Анализатор проверит совместимость.
Обработка None и Optional
Тип Optional[T] эквивалентен Union[T, None]. Это важно для функций, которые могут возвращать None.
def find_user(user_id: int) -> Optional[Dict[str, str]]:
# Логика поиска...
return None
Если функция может вернуть словарь или None, тип возврата должен быть Optional[Dict[str, str]].
Новые возможности union типов (PEP 604)
Начиная с Python 3.10, допускается использование оператора | вместо Union.
def process_input(value: str | int) -> str | int:
if isinstance(value, str):
return value.upper()
return str(value)
В файле builtins.pyi для Python 3.10+ оператор | интерпретируется как объединение типов. Старые версии Python требуют использования typing.Union.
Аналитика поведения функций
Типизация помогает предсказать поведение функций. Например, функция map возвращает итератор, а не список.
def transform_values(data: Dict[str, int]) -> Dict[str, int]:
# map возвращает итератор, поэтому нужно явно преобразовать в dict
return dict(map(lambda k_v: (k_v[0], k_v[1] * 2), data.items()))
Анализатор типов знает, что map возвращает Iterator[T], и требует явного преобразования в dict или list, если ожидается конкретная коллекция.
Различия между версиями Python
Структура builtins.pyi меняется с обновлением языка. Разработчики должны учитывать эти различия.
Версия Python 3.9 и ниже
В старых версиях отсутствовали некоторые новые синтаксические конструкции и типы. Например, использование list[int] вместо List[int] было невозможно. Все типы должны были импортироваться из модуля typing.
Версия Python 3.10
Введена поддержка операторов объединения типов |. Также улучшена типизация встроенных функций, например, int теперь более точно определяет поведение при работе с большими числами.
Версия Python 3.11 и выше
Добавлены новые типы и улучшены существующие сигнатуры. Например, функция input стала более строгой в плане типов возвращаемых значений. Появились новые исключения и оптимизации для встроенных функций.
Синхронизация типов
Использование устаревших файлов builtins.pyi с современной версией Python приводит к ошибкам. Например, если в коде используется dict[str, int], а типы взяты из версии Python 3.8, где такой синтаксис не поддерживается, анализатор выдаст ошибку.
Рекомендуется регулярно обновлять пакеты mypy, pyright и typeshed через менеджер пакетов:
pip install --upgrade mypy
pip install --upgrade typeshed-client
Практические примеры типизации
Ниже приведены примеры кода, демонстрирующие правильное использование встроенных типов и функций в контексте статического анализа.
Пример 1: Работа со списками и словарями
from typing import List, Dict, Any
def aggregate_scores(scores: List[float]) -> Dict[str, float]:
if not scores:
return {"average": 0.0, "max": 0.0, "min": 0.0}
total: float = sum(scores)
average: float = total / len(scores)
maximum: float = max(scores)
minimum: float = min(scores)
return {
"average": average,
"max": maximum,
"min": minimum
}
В этом примере все встроенные функции (sum, len, max, min) имеют строгие сигнатуры в builtins.pyi. Анализатор проверяет, что переданные списки содержат числа, а возвращаемый словарь имеет правильные типы значений.
Пример 2: Обработка исключений
def safe_divide(a: int, b: int) -> float:
try:
return a / b
except ZeroDivisionError:
return 0.0
except TypeError:
return 0.0
Типы исключений ZeroDivisionError и TypeError определены в builtins.pyi. Код обрабатывает возможные ошибки, и анализатор подтверждает, что функция всегда возвращает float.
Пример 3: Использование итераторов
from typing import Iterator, Iterable
def generate_numbers(n: int) -> Iterator[int]:
for i in range(n):
yield i
def consume_iterator(it: Iterator[int]) -> int:
total: int = 0
for num in it:
total += num
return total
Функция range возвращает объект типа range, который является итерируемым. Функция generate_numbers использует yield, создавая итератор. Анализатор типов отслеживает поток данных и гарантирует, что в consume_iterator передается именно итератор целых чисел.