Тут недавно
меня попросили выдать информацию о
происходящем в runtime в Naudoc/Zope. Конкретнее,
что там есть такого в обрабатываемом
документе, в процессе воркфлоу.
Один из простых
способов получить такую информацию
заключается в применении интроспекции.
Недолгое гугление не принесло
исчерпывающего готового рецепта, только
составные части в стиле do it yourself.
Например. Часть
первая
Guide to Python
introspection
How to spy on your
Python objects
Отсюда я взял
первую часть рецепта, добавив в него
чуть-чуть отсебятины, в частности обертку
для перенаправления stdout в список строк
(из
class ListStream: def __init__(self): self.data = [] def write(self, s): self.data.append(s) def interrogate(item): """Print useful information about item. Returns list of strings. """ sys.stdout = x = ListStream() if hasattr(item, '__name__'): print "NAME: ", item.__name__ if hasattr(item, '__class__'): print "CLASS: ", item.__class__.__name__ print "ID: ", id(item) print "TYPE: ", type(item) print "VALUE: ", repr(item) print "CALLABLE:", if callable(item): print "Yes" else: print "No" if hasattr(item, '__doc__'): doc = getattr(item, '__doc__') doc = doc.strip() # Remove leading/trailing whitespace. firstline = doc.split('\n')[0] print "DOC: ", firstline print "ATTRIBUTES:", vars(item) print "NAMES: ", dir(item) sys.stdout = sys.__stdout__ return x.data |
В вывод попало
нечто вроде
NAME: ttt CLASS: HTMLDocument ID: 77748944 TYPE: <type 'ImplicitAcquirerWrapper'> VALUE: <HTMLDocument at /docs/storage/members/valik/test/ttt> CALLABLE: Yes DOC: Subclassed Document type ATTRIBUTES: {'contributors': (), 'nd_uid': '143058357876X4990437627', 'distribution_log': [], '_safety_belt': 'None', 'id': 'ttt', 'subject': (), 'category': 'BGClientCard', '_last_safety_belt': '', 'skip_catalogize': [], 'subscribed_users': {}, '_last_safety_belt_editor': 'zope', '_Delete_objects_Permission': ('Director', 'Manager'), 'text_format': 'html', 'version': <Products.CMFNauTools.ContentVersions.VersionsContainer object at 0x4bf86e0>, '_objects': ({'meta_type': 'Object Manager', 'id': 'version'},), 'followup': <Products.CMFNauTools.TaskItemContainer.TaskItemContainer object at 0x4bc9230>, '_version_tag': -8584773770338532410, 'portal_type': 'HTMLDocument', 'registry_data': {}, 'language': 'ru', 'rights': '', 'expiration_date': None, '_Manage_properties_Permission': ('Author', 'Owner', 'Writer'), '_owner': (['acl_users'], 'zope'), 'changes_log': [], '__ac_local_roles__': {'zope': ['Owner']}} NAMES: ['COPY', 'COPY__roles__', 'Category', 'CategoryAttributes', 'Contributors', 'Contributors__roles__', 'CookedBody', 'CookedBody__roles__', 'CreationDate', 'CreationDate__roles__', 'Creator', 'Creator__roles__', ... |
Заказчику
этого было мало, он захотел получить
сигнатуры методов, в смысле, имена
параметров. На это я ответил, что самый
простой способ получить эту информацию,
это grep по исходному коду.
Но можно иначе.
Например. Часть
вторая
inspect – Inspect
live objects
Purpose: The inspect
module provides functions for introspecting on live objects and their
source code.
If the .py file is
available for a module, the original source code for the class or
method can be retrieved using getsource() and
getsourcelines().
import inspect import example print inspect.getsource(example.A.get_name)
…
In addition to the documentation for a function
or method, it is possible to ask for a complete specification of the
arguments the callable takes, including default values. The
getargspec() function returns a tuple
containing the list of positional argument names, the name of any
variable positional arguments (e.g., *args),
the names of any variable named arguments (e.g., **kwds),
and default values for the arguments. If there are default values,
they match up with the end of the positional argument list.
import inspect import example arg_spec = inspect.getargspec(example.module_level_function) print 'NAMES :', arg_spec[0] print '* :', arg_spec[1] print '** :', arg_spec[2] print 'defaults:', arg_spec[3] args_with_defaults = arg_spec[0][-len(arg_spec[3]):] print 'args & defaults:', zip(args_with_defaults, arg_spec[3])
То есть, получив в первой части список
методов класса, можно скормить его
inspect-у и получить как исходный код, так
и спецификацию аргументов.
Но этого я
делать не стал, грепать попроще таки.
original post http://vasnake.blogspot.com/2015/05/python-introspection.html
Комментариев нет:
Отправить комментарий