关于Introspection :我如何查看Python对象的内部?

How do I look inside a Python object?

我开始使用python(包括django web开发和panda3d游戏开发)编写各种项目的代码。

为了帮助我理解正在发生的事情,我想基本上"查看"一下Python对象内部,看看它们是如何工作的,就像它们的方法和属性一样。

假设我有一个python对象,我需要什么来打印它的内容呢?这是可能的吗?


python有一套很强的内省功能。

查看以下内置功能:

  • type()
  • dir()
  • id()
  • getattr()
  • hasattr()
  • globals()
  • locals()
  • callable()

type()dir()对于分别检查对象类型及其属性集特别有用。


object.__dict__


首先,阅读资料来源。

其次,使用dir()函数。


我很惊讶还没有人提到帮助!

1
2
3
4
5
6
7
8
9
In [1]: def foo():
   ...:    "foo!"
   ...:

In [2]: help(foo)
Help on function foo in module __main__:

foo()
    foo!

帮助让您阅读docstring并了解类可能具有哪些属性,这非常有用。


如果这是为了探索,看看到底发生了什么,我建议你看看伊普敦。这会添加各种快捷方式来获取对象文档、属性甚至源代码。例如,附加"?"函数将为对象提供帮助(实际上是"帮助(obj)"的快捷方式,使用两个?s("EDOCX1〔14])将显示源代码(如果可用)。

还有很多额外的便利,比如制表完成、结果的漂亮打印、结果历史等等,这些都使得这种探索性编程非常方便。

为了更具程序性地使用自省功能,基本的内置功能(如dir()vars()getattr等)将是有用的,但您很值得花时间查看检查模块。要获取函数的源,请使用"inspect.getsource",例如,将其应用于自身:

1
2
3
4
5
6
7
8
9
>>> print inspect.getsource(inspect.getsource)
def getsource(object):
   """Return the text of the source code for an object.

    The argument may be a module, class, method, function, traceback, frame,
    or code object.  The source code is returned as a single string.  An
    IOError is raised if the source code cannot be retrieved."""

    lines, lnum = getsourcelines(object)
    return string.join(lines, '')

如果处理包装或操作函数,inspect.getargspec通常也很有用,因为它将给出函数参数的名称和默认值。


如果您对这个图形用户界面感兴趣,请查看objbrowser。它使用python标准库中的inspect模块进行下面的对象内省。

objbrowserscreenshot


可以在shell中列出dir()对象的属性:

1
2
>>> dir(object())
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

当然,还有inspect模块:http://docs.python.org/library/inspect.html module inspect


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"""Visit http://diveintopython.net/"""

__author__ ="Mark Pilgrim ([email protected])"


def info(object, spacing=10, collapse=1):
   """Print methods and doc strings.

    Takes module, class, list, dictionary, or string."""

    methodList = [e for e in dir(object) if callable(getattr(object, e))]
    processFunc = collapse and (lambda s:"".join(s.split())) or (lambda s: s)
    print"
"
.join(["%s %s" %
                     (method.ljust(spacing),
                      processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])

if __name__ =="__main__":
    print help.__doc__


其他人已经提到了dir()内置的,听起来像是您要找的,但这里还有另一个好提示。许多库(包括大多数标准库)都以源形式分发。这意味着您可以很容易地直接读取源代码。关键在于找到它;例如:

1
2
3
>>> import string
>>> string.__file__
'/usr/lib/python2.5/string.pyc'

已编译*.py c文件,因此请删除尾随的"c",并在最喜爱的编辑器或文件查看器中打开未编译的*.py文件:

1
/usr/lib/python2.5/string.py

我发现这对于发现从给定的API中引发哪些异常非常有用。这种细节在Python世界中很少有很好的文档记录。


试一试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from ppretty import ppretty


class A(object):
    s = 5

    def __init__(self):
        self._p = 8

    @property
    def foo(self):
        return range(10)


print ppretty(A(), indent='    ', depth=2, width=30, seq_length=6,
              show_protected=True, show_private=False, show_static=True,
              show_properties=True, show_address=True)

输出:

1
2
3
4
5
__main__.A at 0x1debd68L (
    _p = 8,
    foo = [0, 1, 2, ..., 7, 8, 9],
    s = 5
)

虽然其他人已经提到了pprint,但我想添加一些上下文。

The pprint module provides a capability to"pretty-print" arbitrary
Python data structures in a form which can be used as input to the
interpreter. If the formatted structures include objects which are not
fundamental Python types, the representation may not be loadable. This
may be the case if objects such as files, sockets, classes, or
instances are included, as well as many other built-in objects which
are not representable as Python constants.

具有PHP背景的开发人员可能对pprint有很高的需求,他们正在寻找替代var_dump()的方案。

使用pprint()vars()混合可以很好地转储具有dict属性的对象,后者返回模块、类、实例等的__dict__属性:

1
2
from pprint import pprint
pprint(vars(your_object))

所以,不需要循环。

要转储全局或本地作用域中包含的所有变量,只需使用:

1
2
pprint(globals())
pprint(locals())

locals()显示函数中定义的变量。除了其他用法外,使用相应的名称作为字符串键访问函数也很有用:

1
2
locals()['foo']() # foo()
globals()['foo']() # foo()

同样,使用dir()查看模块的内容或对象的属性。

还有更多。


如果您想查看参数和方法,正如其他人指出的那样,您可以使用pprintdir()

如果要查看内容的实际值,可以

object.__dict__


有一个python代码库构建就是为了这个目的:在python 2.7中引入了inspect


检查代码的两个重要工具是:

  • iPython。允许您使用制表符完成检查的python终端。

  • 带有pydev插件的Eclipse。它有一个优秀的调试器,允许您在给定的位置中断,并通过将所有变量浏览为树来检查对象。甚至可以使用嵌入式终端在该位置尝试代码,或者键入对象并按"."让它为您提供代码提示。

  • enter image description here


    PPRINT和DIR一起工作很好


    如果您想查看与对象myobj对应的函数源代码,可以输入iPythonJupyter Notebook

    myobj??


    vars(obj)返回对象的属性。


    1
    2
    3
    import pprint

    pprint.pprint(obj.__dict__)

    1
    pprint.pprint(vars(obj))


    如果您想查看活动对象的内部,那么python的inspect模块是一个很好的答案。通常,它用于获取在磁盘上某个源文件中定义的函数的源代码。如果您想获得在解释器中定义的活动函数和lambda的源代码,可以从dill中使用dill.source.getsource。它还可以从课程表中定义的绑定或未绑定类方法和函数中获取代码。但是,如果没有封闭对象的代码,则可能无法编译该代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    >>> from dill.source import getsource
    >>>
    >>> def add(x,y):
    ...   return x+y
    ...
    >>> squared = lambda x:x**2
    >>>
    >>> print getsource(add)
    def add(x,y):
      return x+y

    >>> print getsource(squared)
    squared = lambda x:x**2

    >>>
    >>> class Foo(object):
    ...   def bar(self, x):
    ...     return x*x+x
    ...
    >>> f = Foo()
    >>>
    >>> print getsource(f.bar)
    def bar(self, x):
        return x*x+x

    >>>


    此外,如果要查看列表和字典,可以使用pprint()。


    尝试使用:

    1
    print(object.stringify())
    • 其中,object是要检查的对象的变量名。

    这将打印出一个格式良好的选项卡式输出,显示对象中键和值的所有层次结构。

    注:本品适用于python3。不确定它是否适用于早期版本