Перейти к основному содержимому

Встроенный модуль 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__boolTrue, если 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 передается именно итератор целых чисел.