Записки программиста, обо всем и ни о чем. Но, наверное, больше профессионального.

2015-05-08

Python introspection

Тут недавно меня попросили выдать информацию о происходящем в 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

Комментариев нет:

Отправить комментарий

Архив блога

Ярлыки

linux (241) python (191) citation (186) web-develop (170) gov.ru (159) video (124) бытовуха (115) sysadm (100) GIS (97) Zope(Plone) (88) бурчалки (84) Book (83) programming (82) грабли (77) Fun (76) development (73) windsurfing (72) Microsoft (64) hiload (62) internet provider (57) opensource (57) security (57) опыт (55) movie (52) Wisdom (51) ML (47) driving (45) hardware (45) language (45) money (42) JS (41) curse (40) bigdata (39) DBMS (38) ArcGIS (34) history (31) PDA (30) howto (30) holyday (29) Google (27) Oracle (27) tourism (27) virtbox (27) health (26) vacation (24) AI (23) Autodesk (23) SQL (23) Java (22) humor (22) knowledge (22) translate (20) CSS (19) cheatsheet (19) hack (19) Apache (16) Manager (15) web-browser (15) Никонов (15) Klaipeda (14) functional programming (14) happiness (14) music (14) todo (14) PHP (13) course (13) scala (13) weapon (13) HTTP. Apache (12) SSH (12) frameworks (12) hero (12) im (12) settings (12) HTML (11) SciTE (11) USA (11) crypto (11) game (11) map (11) HTTPD (9) ODF (9) Photo (9) купи/продай (9) benchmark (8) documentation (8) 3D (7) CS (7) DNS (7) NoSQL (7) cloud (7) django (7) gun (7) matroska (7) telephony (7) Microsoft Office (6) VCS (6) bluetooth (6) pidgin (6) proxy (6) Donald Knuth (5) ETL (5) NVIDIA (5) Palanga (5) REST (5) bash (5) flash (5) keyboard (5) price (5) samba (5) CGI (4) LISP (4) RoR (4) cache (4) car (4) display (4) holywar (4) nginx (4) pistol (4) spark (4) xml (4) Лебедев (4) IDE (3) IE8 (3) J2EE (3) NTFS (3) RDP (3) holiday (3) mount (3) Гоблин (3) кухня (3) урюк (3) AMQP (2) ERP (2) IE7 (2) NAS (2) Naudoc (2) PDF (2) address (2) air (2) british (2) coffee (2) fitness (2) font (2) ftp (2) fuckup (2) messaging (2) notify (2) sharepoint (2) ssl/tls (2) stardict (2) tests (2) tunnel (2) udev (2) APT (1) CRUD (1) Canyonlands (1) Cyprus (1) DVDShrink (1) Jabber (1) K9Copy (1) Matlab (1) Portugal (1) VBA (1) WD My Book (1) autoit (1) bike (1) cannabis (1) chat (1) concurrent (1) dbf (1) ext4 (1) idioten (1) join (1) krusader (1) license (1) life (1) migration (1) mindmap (1) navitel (1) pneumatic weapon (1) quiz (1) regexp (1) robot (1) science (1) serialization (1) spatial (1) tie (1) vim (1) Науру (1) крысы (1) налоги (1) пианино (1)