Язык программирования Python

       

Модуль inspect


Основное назначение модуля inspect - давать приложению информацию о модулях, классах, функциях, трассировочных объектах, фреймах исполнения и кодовых объектах. Именно модуль inspect позволяет заглянуть "на кухню" интерпретатора Python.

Модуль имеет функции для проверки принадлежности объектов различным типам, с которыми он работает:

ФункцияПроверяемый тип
inspect.isbuiltinВстроенная функция
inspect.isclassКласс
inspect.iscodeКод
inspect.isdatadescriptorОписатель данных
inspect.isframeФрейм
inspect.isfunctionФункция
inspect.ismethodМетод
inspect.ismethoddescriptorОписатель метода
inspect.ismoduleМодуль
inspect.isroutineФункция или метод
inspect.istracebackТрассировочный объект

Пример:

>>> import inspect >>> inspect.isbuiltin(len) True >>> inspect.isroutine(lambda x: x+1) True >>> inspect.ismethod(''.split) False >>> inspect.isroutine(''.split) True >>> inspect.isbuiltin(''.split) True

Объект типа модуль появляется в Python-программе благодаря операции импорта. Для получения информации о модуле имеются некоторые функции, а объект-модуль обладает определенными атрибутами, как продемонстрировано ниже:

>>> import inspect >>> inspect.ismodule(inspect) True >>> inspect.getmoduleinfo('/usr/local/lib/python2.3/inspect.pyc') ('inspect', '.pyc', 'rb', 2) >>> inspect.getmodulename('/usr/local/lib/python2.3/inspect.pyc') 'inspect' >>> inspect.__name__ 'inspect' >>> inspect.__dict__ . . . >>> inspect.__doc__ "Get useful information from live Python objects.\n\nThis module encapsulates .. . .

Интересны некоторые функции, которые предоставляют информацию об исходном коде объектов:

>>> import inspect >>> inspect.getsourcefile(inspect) # имя файла исходного кода '/usr/local/lib/python2.3/inspect.py' >>> inspect.getabsfile(inspect) # абсолютный путь к файлу '/usr/local/lib/python2.3/inspect.py' >>> print inspect.getfile(inspect) # файл кода модуля /usr/local/lib/python2.3/inspect.pyc >>> print inspect.getsource(inspect) # исходный текст модуля (в виде строки) # -*- coding: iso-8859-1 -*- """Get useful information from live Python objects. . . . >>> import smtplib >>> # Комментарий непосредственно перед определением объекта: >>> inspect.getcomments(smtplib.SMTPException) '# Exception classes used by this module.\n' >>> # Теперь берем строку документирования: >>> inspect.getdoc(smtplib.SMTPException) 'Base class for all exceptions raised by this module.'


С помощью модуля inspect можно узнать состав аргументов некоторой функции с помощью функции inspect.getargspec():

>>> import inspect >>> def f(x, y=1, z=2): ... return x + y + z ... >>> def g(x, *v, **z): ... return x ... >>> print inspect.getargspec(f) (['x', 'y', 'z'], None, None, (1, 2)) >>> print inspect.getargspec(g) (['x'], 'v', 'z', None)

Возвращаемый кортеж содержит список аргументов (кроме специальных), затем следуют имена аргументов для списка позиционных аргументов (*) и списка именованных аргументов (**), после чего - список значений по умолчанию для последних позиционных аргументов. Первый аргумент-список может содержать вложенные списки, отражая структуру аргументов:

>>> def f((x1,y1), (x2,y2)): ... return 1 ... >>> print inspect.getargspec(f) ([['x1', 'y1'], ['x2', 'y2']], None, None, None)

Классы (как вы помните) - тоже объекты, и о них можно кое-что узнать:



>>> import smtplib >>> s = smtplib.SMTP >>> s.__module__ # модуль, в котором был определен объект 'smtplib' >>> inspect.getmodule(s) # можно догадаться о происхождении объекта <module 'smtplib' from '/usr/local/lib/python2.3/smtplib.pyc'>

Для визуализации дерева классов может быть полезна функция inspect.getclasstree(). Она возвращает иерархически выстроенный в соответствии с наследованием список вложенных списков классов, указанных в списке-параметре. В следующем примере на основе списка всех встроенных классов-исключений создается дерево их зависимостей по наследованию:

import inspect, exceptions

def formattree(tree, level=0): """Вывод дерева наследований. tree - дерево, подготовленное с помощью inspect.getclasstree(), которое представлено списком вложенных списков и кортежей. В кортеже entry первый элемент - класс, а второй - кортеж с его базовыми классами. Иначе entry - вложенный список. level - уровень отступов """ for entry in tree: if type(entry) is type(()): c, bases = entry print level * " ", c.__name__, \ "(" + ", ".join([b.__name__ for b in bases]) + ")" elif type(entry) is type([]): formattree(entry, level+1)



v = exceptions.__dict__.values() exc_list = [e for e in v if inspect.isclass(e) and issubclass(e, Exception)]

formattree(inspect.getclasstree(exc_list))

С помощью функции inspect.currentframe() можно получить текущий фрейм исполнения. Атрибуты фрейма исполнения дают информацию о блоке кода, исполняющегося в точке вызова метода. При вызове функции (и в некоторых других ситуациях) на стек кладется соответствующий этому фрейму блок кода. При возврате из функции текущим становится фрейм, хранившийся в стеке. Фрейм содержит контекст выполнения кода: пространства имен и некоторые другие данные. Получить эти данные можно через атрибуты фреймового объекта:

import inspect

def f(): fr = inspect.currentframe() for a in dir(fr): if a[:2] != "__": print a, ":", str(getattr(fr, a))[:70]

f()

В результате получается

f_back : <frame object at 0x812383c> f_builtins : {'help': Type help() for interactive help, or help(object) for help ab f_code : <code object f at 0x401d83a0, file "<stdin>", line 11> f_exc_traceback : None f_exc_type : None f_exc_value : None f_globals : {'f': <function f at 0x401e0454>, '__builtins__': <module '__builtin__ f_lasti : 68 f_lineno : 16 f_locals : {'a': 'f_locals', 'fr': <frame object at 0x813c34c>} f_restricted : 0 f_trace : None

Здесь f_back - предыдущий фрейм исполнения (вызвавший данный фрейм), f_builtins - пространство встроенных имен, как его видно из данного фрейма, f_globals - пространство глобальных имен, f_locals - пространство локальных имен, f_code - кодовый объект (в данном случае - байт-код функции f()), f_lasti - индекс последней выполнявшейся инструкции байт-кода, f_trace - функция трассировки для данного фрейма (или None), f_lineno - текущая строка исходного кода, f_restricted - признак выполнения в ограничительном режиме.

Получить информацию о стеке интерпретатора можно с помощью функции inspect.stack(). Она возвращает список кортежей, в которых есть следующие элементы:



(фрейм-объект, имя_файла, строка_в_файле, имя_функции, список_строк_исходного_кода, номер_строки_в_коде)

Трассировочные объекты также играют важную роль в интроспективных возможностях языка Python: с их помощью можно отследить место возбуждения исключения и обработать его требуемым образом. Для работы с трассировками предусмотрен даже специальный модуль - traceback.

Трассировочный объект представляет содержимое стека исполнения от места возбуждения исключения до места его обработки. В обработчике исключений связанный с исключением трассировочный объект доступен посредством функции sys.exc_info() (это третий элемент возвращаемого данной функцией кортежа).

Трассировочный объект имеет следующие атрибуты:

  • tb_frame Фрейм исполнения текущего уровня.
  • tb_lineno и tb_lasti Номер строки и инструкции, где было возбуждено исключение.
  • tb_next Следующий уровень стека (другой трассировочный объект).


Одно из наиболее частых применений модуля traceback - "мягкая" обработка исключений с выводом отладочной информации в удобном виде (в лог, на стандартный вывод ошибок и т.п.):

#!/usr/bin/python

def dbg_except(): """Функция для отладки операторов try-except""" import traceback, sys, string print sys.exc_info() print " ".join(traceback.format_exception(*sys.exc_info()))

def bad_func2(): raise StandardError

def bad_func(): bad_func2()

try: bad_func() except: dbg_except()

В результате получается примерно следующее:

(<class exceptions.StandardError at 0x4019729c>, <exceptions.StandardError instance at 0x401df2cc>, <traceback object at 0x401dcb1c>) Traceback (most recent call last): File "pr143.py", line 17, in ? bad_func() File "pr143.py", line 14, in bad_func bad_func2() File "pr143.py", line 11, in bad_func2 raise StandardError StandardError

Функция sys.exc_info() дает кортеж с информацией о возбужденном исключении (класс исключения, объект исключения и трассировочный объект). Элементы этого кортежа передаются как параметры функции traceback.format_exception(), которая и печатает информацию об исключении в уже знакомой форме.Модуль traceback содержит и другие функции (о них можно узнать из документации), которые помогают форматировать те или иные части информации об исключении.

Разумеется, это еще не все возможности модуля inspect и свойств интроспекции в Python, а лишь наиболее интересные функции и атрибуты. Подробнее можно прочитать в документации или даже в исходном коде модулей стандартной библиотеки Python.


Содержание раздела