Inspect.getsource: примеры (PYTHON)
inspect.getsource(object: callable): strОписание функции inspect.getsource
Функция inspect.getsource является частью стандартного модуля inspect в Python. Ее основное назначение - получение исходного текста (исходного кода) объекта, такого как функция, метод, класс, модуль или объект трассировки. Этот инструмент часто применяется при отладке, создании инструментов для анализа кода, документации или метапрограммирования.
Функция позволяет извлекать код из исходных файлов, что делает ее полезной для интроспекции во время выполнения программы. Она работает только с объектами, исходный код которых доступен (написан на Python и загружен из файла). Для встроенных функций и объектов, написанных на C, функция не сможет получить исходный текст.
Аргументы функции
getsource(object) принимает один обязательный аргумент:
- object - объект, для которого необходимо получить исходный код. Это может быть модуль, класс, метод, функция, генератор, асинхронная функция, трассировка или фрейм.
Возвращаемое значение
Функция возвращает строку (str), содержащую исходный текст объекта. Если исходный код получить невозможно, функция вызывает исключение OSError (для объектов, не определенных в исходном файле) или TypeError (если передан неподходящий объект).
Простые примеры использования
Ниже представлены базовые варианты применения функции inspect.getsource.
Пример 1: Получение кода простой функции.
import inspect
def example_func(a, b):
"""Возвращает сумму a и b."""
return a + b
source = inspect.getsource(example_func)
print(source)def example_func(a, b):
"""Возвращает сумму a и b."""
return a + bПример 2: Получение кода класса и его метода.
import inspect
class SampleClass:
"""Простой класс для демонстрации."""
def __init__(self, value):
self.value = value
def display(self):
return f"Value: {self.value}"
# Код класса
class_source = inspect.getsource(SampleClass)
print("Код класса:")
print(class_source)
# Код метода
method_source = inspect.getsource(SampleClass.display)
print("\nКод метода display:")
print(method_source)Код класса:
class SampleClass:
"""Простой класс для демонстрации."""
def __init__(self, value):
self.value = value
def display(self):
return f"Value: {self.value}"
Код метода display:
def display(self):
return f"Value: {self.value}"Похожие функции в Python
Модуль inspect предлагает другие функции для интроспекции, которые могут быть полезны в различных сценариях.
- inspect.getsourcefile(object): Возвращает имя файла, в котором определен объект. Подходит для определения местоположения исходного кода. Используется, когда нужен только путь к файлу, а не сам код.
- inspect.getsourcelines(object): Возвращает кортеж (список строк исходного кода, номер начальной строки). Полезно, когда требуется знать, с какой строки начинается определение объекта.
- inspect.getdoc(object): Получает строку документации объекта. Применяется для извлечения docstring без всего исходного кода.
- __code__ атрибут функций: Позволяет получить байт-код и другую низкоуровневую информацию, но не исходный текст. Используется для более глубокого анализа выполнения.
Функцию getsource выбирают, когда необходим именно читаемый исходный код объекта. getsourcelines удобнее для отображения кода с номерами строк, а getsourcefile - для логирования или отладки путей.
Аналоги в других языках программирования
Возможность получить исходный код во время выполнения поддерживается не во всех языках, часто из-за компилируемой природы или ограничений среды.
JavaScript: В стандарте нет прямой аналогии. Однако в среде Node.js можно использовать fs.readFileSync для загрузки файлов, если известен путь. Функция toString(), примененная к функции, возвращает ее строковое представление, которое может содержать исходный код, но зависит от реализации.
// Пример в JavaScript (Node.js)
function example(a, b) {
return a + b;
}
console.log(example.toString());function example(a, b) {
return a + b;
}PHP: Функция ReflectionFunction::getFileName() и getStartLine()/getEndLine() позволяют получить расположение кода. Для получения самого кода нужно читать файл самостоятельно.
// Пример в PHP
function example($a, $b) {
return $a + $b;
}
$reflection = new ReflectionFunction('example');
echo $reflection->getFileName() . "\n";
echo $reflection->getStartLine();/path/to/file.php 3
Java: В стандартной библиотеке нет функции для получения исходного кода. Инструменты рефлексии позволяют получать метаинформацию, но не исходный текст. Исходный код обычно недоступен во время выполнения.
Golang: Пакет runtime позволяет получить информацию о стеке вызовов и именах функций, но не исходный код. Стандартного способа получить исходный текст функции нет.
Таким образом, inspect.getsource в Python предлагает уникальную, высокоуровневую возможность, которая редко встречается в таком виде в других языках, особенно компилируемых.
Типичные ошибки и исключения
При использовании inspect.getsource можно столкнуться с несколькими распространенными ошибками.
Ошибка 1: Попытка получить исходный код встроенного или скомпилированного объекта.
import inspect
# Встроенная функция print
source = inspect.getsource(print)
print(source)OSError: could not get source code
Ошибка 2: Передача экземпляра класса вместо самого класса или метода.
import inspect
class MyClass:
pass
obj = MyClass()
source = inspect.getsource(obj) # Передан экземплярTypeError: <__main__.MyClass object at 0x...> is not a module, class, method, function, traceback, frame, or code object
Ошибка 3: Объект определен в интерактивной оболочке или через exec().
import inspect
code = """
def dynamic_func():
return 42
"""
exec(code)
# dynamic_func существует, но определен динамически
source = inspect.getsource(dynamic_func)OSError: could not get source code
Чтобы избежать ошибок, рекомендуется проверять тип объекта или обрабатывать исключения с помощью try-except.
Изменения в последних версиях
Функция inspect.getsource остается стабильной и не претерпела значительных изменений в последних основных версиях Python. Ее API (один аргумент) и поведение сохраняются.
Однако, стоит отметить общие изменения в модуле inspect, связанные с поддержкой новых возможностей языка. Например, в Python 3.5+ функция корректно работает с асинхронными функциями (async def) и корутинами. В Python 3.8+ улучшена работа с объектами трассировки.
Важно, что функция по-прежнему зависит от наличия исходных файлов (.py) и не работает с кодом, загруженным из скомпилированных байт-код файлов (.pyc), если исходный файл отсутствует.
Расширенные и специальные примеры
Пример 1: Работа с декорированными функциями. getsource возвращает код функции вместе с примененными к ней декораторами.
import inspect
def decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@decorator
def decorated_sum(a, b):
"""Суммирует два числа."""
return a + b
source = inspect.getsource(decorated_sum)
print(source)@decorator
def decorated_sum(a, b):
"""Суммирует два числа."""
return a + bПример 2: Получение кода лямбда-функции. Хотя лямбда-функции анонимны, getsource может получить строку, где они определены.
import inspect
square = lambda x: x ** 2
source = inspect.getsource(square)
print(source)square = lambda x: x ** 2
Пример 3: Использование getsource для генерации документации. Можно автоматически извлекать сигнатуры функций для создания API-документов.
import inspect
def complex_calc(rate: float, periods: int) -> float:
"""
Вычисляет сложный процент.
Args:
rate: Процентная ставка.
periods: Количество периодов.
Returns:
Итоговый коэффициент.
"""
return (1 + rate) ** periods
def generate_docs(func):
source = inspect.getsource(func).split('\n')[0] # Первая строка с сигнатурой
doc = inspect.getdoc(func)
return f"Сигнатура: {source}\n\nОписание:\n{doc}"
print(generate_docs(complex_calc))Сигнатура: def complex_calc(rate: float, periods: int) -> float:
Описание:
Вычисляет сложный процент.
Args:
rate: Процентная ставка.
periods: Количество периодов.
Returns:
Итоговый коэффициент.Пример 4: Анализ кода с помощью getsource и getsourcelines. Определение размера функции в строках кода.
import inspect
def lengthy_function():
a = 1
b = 2
c = a + b
for i in range(10):
print(i)
return c
lines, start_line = inspect.getsourcelines(lengthy_function)
print(f"Функция начинается со строки {start_line}")
print(f"Длина функции в строках: {len(lines)}")
print("Последняя строка тела функции:", lines[-1].rstrip())Функция начинается со строки 1 Длина функции в строках: 9 Последняя строка тела функции: return c
Пример 5: Получение кода асинхронной функции.
import inspect
import asyncio
async def fetch_data(url):
"""Асинхронно получает данные."""
# Имитация запроса
await asyncio.sleep(0.1)
return f"data from {url}"
source = inspect.getsource(fetch_data)
print(source)async def fetch_data(url):
"""Асинхронно получает данные."""
# Имитация запроса
await asyncio.sleep(0.1)
return f"data from {url}"