python自省相关函数sys/help/。。

什么是自省?

在日常生活中,自省(introspection)是一种自我检查行为。自省是指对某人自身思想、情绪、动机和行为的检查。伟大的哲学家苏格拉底将生命中的大部分时间用于自我检查,并鼓励他的雅典朋友们也这样做。他甚至对自己作出了这样的要求:“未经自省的生命不值得存在。”(请参阅参考资料以获取关于苏格拉底更多信息的链接。)

在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。一旦您使用了支持自省的编程语言,就会产生类似这样的感觉:“未经检查的对象不值得实例化。”

本文介绍了 Python 编程语言的自省能力。整个 Python 语言对自省提供了深入而广泛的支持。实际上,很难想象假如 Python 语言没有其自省特性是什么样子。在读完本文时,您应该能够非常轻松地洞察到自己 Python 对象的“灵魂”。

在深入研究更高级的技术之前,我们尽可能用最普通的方式来研究 Python 自省。有些读者甚至可能会争论说:我们开始时所讨论的特性不应称之为“自省”。我们必须承认,它们是否属于自省的范畴还有待讨论。但从本文的主旨出发,我们所关心的只是找出有趣问题的答案。

现在让我们以交互方式使用 Python 来开始研究。当我们从命令行启动 Python 时,就进入了 Python shell,在这里可以输入 Python 代码,而且立刻会从 Python 解释器获得响应。(本文中列出的命令可以使用 Python 2.2.2 正确执行。如果您使用较早的版本,则可能产生不同的结果或发生错误。可以从 Python 网站下载最新版本 [请参阅参考资料]。)

清单 1. 以交互方式启动 Python 解释器
$ python
Python 2.2.2 (#1, Oct 28 2002, 17:22:19)
[GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

在让 Python 运行起来,并看到 Python 提示符(>>>)之后,您可能想知道 Python 能识别什么字。大多数编程语言都有保留字或关键字,这些字在该语言中有特殊的意义,Python 也不例外。您可能还注意到,Python 建议我们输入 help 以获取更多信息。也许我们可以向 Python 寻求一些关于关键字的帮助。


Python 的联机帮助实用程序

让我们按建议的那样,通过输入 help 来开始讨论,并观察它是否会向我们提供任何关于关键字的线索:

清单 2. 向 Python 寻求帮助
>>> help
Type help() for interactive help, or help(object) for help about object.

因为我们不知道哪些对象可能包含关键字,所以不指定任何特定对象来尝试 help()

清单 3. 启动帮助实用程序
>>> help()
Welcome to Python 2.2!  This is the online help utility.
If this is your first time using Python, you should definitely check out
the tutorial on the Internet at http://www.python.org/doc/tut/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules.  To quit this help utility and
return to the interpreter, just type "quit".
To get a list of available modules, keywords, or topics, type "modules",
"keywords", or "topics".  Each module also comes with a one-line summary
of what it does; to list the modules whose summaries contain a given word
such as "spam", type "modules spam".
help>

现在,我们对此的理解似乎深入了些。让我们在 help 提示符下输入 keywords

清单 4. 用 keywords 寻求帮助
help> keywords
Here is a list of the Python keywords.  Enter any keyword to get more help.
and                 elif                global              or
assert              else                if                  pass
break               except              import              print
class               exec                in                  raise
continue            finally             is                  return
def                 for                 lambda              try
del                 from                not                 while
help> quit
You are now leaving help and returning to the Python interpreter.
If you want to ask for help on a particular object directly from the
interpreter, you can type "help(object)".  Executing "help('string')"
has the same effect as typing a particular string at the help> prompt.
>>>

输入 help() 后,会看到一条欢迎消息和一些指示信息,接着是 help 提示符。在提示符下输入 keywords,则会看到一个 Python 关键字列表。我们已经获得了问题的答案,于是退出帮助实用程序,这时会看到一条简短的告别消息,并返回到 Python 提示符下。

正如您从这个示例可以看到的,Python 的联机帮助实用程序会显示关于各种主题或特定对象的信息。帮助实用程序很有用,并确实利用了 Python 的自省能力。但仅仅使用帮助不会揭示帮助是如何获得其信息的。而且,因为本文的目的是揭示 Python 自省的所有秘密,所以我们必须迅速地跳出对帮助实用程序的讨论。

在结束关于帮助的讨论之前,让我们用它来获得一个可用模块的列表。模块只是包含 Python 代码的文本文件,其名称后缀是 .py。如果在 Python 提示符下输入 help('modules'),或在 help 提示符下输入 modules,则会看到一长列可用模块,类似于下面所示的部分列表。自己尝试它以观察您的系统中有哪些可用模块,并了解为什么会认为 Python 是“自带电池”的。

清单 5. 部分可用模块的列表
>>> help('modules')
Please wait a moment while I gather a list of all available modules...
BaseHTTPServer      cgitb               marshal             sndhdr
Bastion             chunk               math                socket
CDROM               cmath               md5                 sre
CGIHTTPServer       cmd                 mhlib               sre_compile
Canvas              code                mimetools           sre_constants
	<...>
bisect              macpath             signal              xreadlines
cPickle             macurl2path         site                xxsubtype
cStringIO           mailbox             slgc (package)      zipfile
calendar            mailcap             smtpd
cgi                 markupbase          smtplib
Enter any module name to get more help.  Or, type "modules spam" to search
for modules whose descriptions contain the word "spam".
>>>

sys 模块

sys 模块是提供关于 Python 本身的详尽内在信息的模块。通过导入模块,并用点(.)符号引用其内容(如变量、函数和类)来使用模块。sys 模块包含各种变量和函数,它们揭示了当前的 Python 解释器有趣的详细信息。让我们研究其中的一部分。我们要再次以交互方式运行 Python,并在 Python 命令提示符下输入命令。首先,我们将导入 sys 模块。然后,我们会输入 sys.executable 变量,它包含到 Python 解释器的路径:

清单 6. 导入 sys 模块
$ python
Python 2.2.2 (#1, Oct 28 2002, 17:22:19)
[GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.executable
'/usr/local/bin/python'

当输入一行只包含对象名称的代码时,Python 通过显示该对象的表示进行响应,对于简单对象,往往显示对象的值。在本例中,因为所显示的值是用引号括起来的,所以我们得到一条线索:sys.executable 可能是字符串对象。稍后,我们将研究确定对象类型的其它更精确的方法,但只在 Python 提示符下输入对象名称是一种迅速而又方便的自省形式。

让我们研究 sys 模块其它一些有用的属性。

platform 变量告诉我们现在处于什么操作系统上:

sys.platform 属性
>>> sys.platform
'linux2'

在当前的 Python 中,版本以字符串和元组(元组包含对象序列)来表示:

清单 8. sys.version 和 sys.version_info 属性
>>> sys.version
'2.2.2 (#1, Oct 28 2002, 17:22:19) \n[GCC 3.2 (Mandrake Linux 9.0 3.2-1mdk)]'
>>> sys.version_info
(2, 2, 2, 'final', 0)

maxint 变量反映了可用的最大整数值:

sys.maxint 属性
>>> sys.maxint
2147483647

argv 变量是一个包含命令行参数的列表(如果参数被指定的话)。第一项 argv[0] 是所运行脚本的路径。当我们以交互方式运行 Python 时,这个值是空字符串:

清单 10. sys.argv 属性
>>> sys.argv
['']

当运行其它 Python shell 时,如 PyCrust(有关 PyCrust 更多信息的链接,请参阅参考资料),会看到类似于下面的信息:

清单 11. 使用 PyCrust 时的 sys.argv 属性
>>> sys.argv[0]
'/home/pobrien/Code/PyCrust/PyCrustApp.py'

path 变量是模块搜索路径,Python 在导入期间将在其中的目录列表中寻找模块。最前面的空字符串 '' 是指当前目录:

清单 12. sys.path 属性
>>> sys.path
['', '/home/pobrien/Code',
'/usr/local/lib/python2.2',
'/usr/local/lib/python2.2/plat-linux2',
'/usr/local/lib/python2.2/lib-tk',
'/usr/local/lib/python2.2/lib-dynload',
'/usr/local/lib/python2.2/site-packages']

modules 变量是一个字典,它将当前已装入的所有模块的名称映射到模块对象。如您所见,缺省情况下,Python 装入一些特定的模块:

清单 13. sys.modules 属性
>>> sys.modules
{'stat': <module 'stat' from '/usr/local/lib/python2.2/stat.pyc'>,
'__future__': <module '__future__' from '/usr/local/lib/python2.2/__future__.pyc'>,
'copy_reg': <module 'copy_reg' from '/usr/local/lib/python2.2/copy_reg.pyc'>,
'posixpath': <module 'posixpath' from '/usr/local/lib/python2.2/posixpath.pyc'>,
'UserDict': <module 'UserDict' from '/usr/local/lib/python2.2/UserDict.pyc'>,
'signal': <module 'signal' (built-in)>,
'site': <module 'site' from '/usr/local/lib/python2.2/site.pyc'>,
'__builtin__': <module '__builtin__' (built-in)>,
'sys': <module 'sys' (built-in)>,
'posix': <module 'posix' (built-in)>,
'types': <module 'types' from '/usr/local/lib/python2.2/types.pyc'>,
'__main__': <module '__main__' (built-in)>,
'exceptions': <module 'exceptions' (built-in)>,
'os': <module 'os' from '/usr/local/lib/python2.2/os.pyc'>,
'os.path': <module 'posixpath' from '/usr/local/lib/python2.2/posixpath.pyc'>}

keyword 模块

让我们返回到关于 Python 关键字的问题。尽管帮助向我们显示了关键字列表,但事实证明一些帮助信息是硬编码的。关键字列表恰好是硬编码的,但毕竟它的自省程度不深。让我们研究一下,能否直接从 Python 标准库的某个模块中获取这个信息。如果在 Python 提示符下输入 help('modules keywords'),则会看到如下信息:

清单 14. 同时使用 modules 和 keywords 寻求帮助
>>> help('modules keywords')
Here is a list of matching modules.  Enter any module name to get more help.
keyword - Keywords (from "graminit.c")

看起来,keyword 模块好象包含关键字。在文本编辑器中打开 keyword.py 文件,我们可以看到,Python 确实可以把关键字列表显式地用作 keyword 模块的 kwlist 属性。在 keyword 模块的注释中,我们还可以看到,该模块是根据 Python 本身的源代码自动生成的,这可以保证其关键字列表是准确而完整的:

清单 15. keyword 模块的关键字列表
>>> import keyword
>>> keyword.kwlist
['and', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else',
'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is',
'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'yield']

dir() 函数

尽管查找和导入模块相对容易,但要记住每个模块包含什么却不是这么简单。您并不希望总是必须查看源代码来找出答案。幸运的是,Python 提供了一种方法,可以使用内置的 dir() 函数来检查模块(以及其它对象)的内容。

dir() 函数可能是 Python 自省机制中最著名的部分了。它返回传递给它的任何对象的属性名称经过排序的列表。如果不指定对象,则 dir() 返回当前作用域中的名称。让我们将 dir() 函数应用于 keyword 模块,并观察它揭示了什么:

清单 16. keyword 模块的属性
>>> dir(keyword)
['__all__', '__builtins__', '__doc__', '__file__', '__name__',
'iskeyword', 'keyword', 'kwdict', 'kwlist', 'main']

那么将它应用于我们先前讨论的 sys 模块会怎么样呢?

清单 17. sys 模块的属性
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__',
'__stdin__', '__stdout__', '_getframe', 'argv', 'builtin_module_names',
'byteorder', 'copyright', 'displayhook', 'exc_info', 'exc_type', 'excepthook',
'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags',
'getrecursionlimit', 'getrefcount', 'hexversion', 'last_traceback',
'last_type', 'last_value', 'maxint', 'maxunicode', 'modules', 'path',
'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout',
'version', 'version_info', 'warnoptions']

如果不带任何参数,则 dir() 返回当前作用域中的名称。请注意,因为我们先前导入了 keywordsys,所以它们出现在列表中。导入模块将把该模块的名称添加到当前作用域:

清单 18. 当前作用域中的名称
>>> dir()
['__builtins__', '__doc__', '__name__', 'keyword', 'sys']

我们曾经提到 dir() 函数是内置函数,这意味着我们不必为了使用该函数而导入模块。不必做任何操作,Python 就可识别内置函数。现在,我们看到调用 dir() 后返回了这个名称 __builtins__。也许此处有连接。让我们在 Python 提示符下输入名称 __builtins__,并观察 Python 是否会告诉我们关于它的任何有趣的事情:

清单 19. __builtins__ 是什么?
>>> __builtins__
<module '__builtin__' (built-in)>

因此 __builtins__ 看起来象是当前作用域中绑定到名为 __builtin__ 的模块对象的名称。(因为模块不是只有多个单一值的简单对象,所以 Python 改在尖括号中显示关于模块的信息。)注:如果您在磁盘上寻找 __builtin__.py 文件,将空手而归。这个特殊的模块对象是 Python 解释器凭空创建的,因为它包含着解释器始终可用的项。尽管看不到物理文件,但我们仍可以将 dir() 函数应用于这个对象,以观察所有内置函数、错误对象以及它所包含的几个杂项属性。

清单 20. __builtins__ 模块的属性
>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning',
'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
'FloatingPointError', 'IOError', 'ImportError', 'IndentationError',
'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError',
'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError',
'OverflowError', 'OverflowWarning', 'ReferenceError', 'RuntimeError',
'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError',
'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError',
'UnboundLocalError', 'UnicodeError', 'UserWarning', 'ValueError', 'Warning',
'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', '__name__',
'abs', 'apply', 'bool', 'buffer', 'callable', 'chr', 'classmethod', 'cmp',
'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict',
'dir', 'divmod', 'eval', 'execfile', 'exit', 'file', 'filter', 'float',
'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int',
'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list',
'locals', 'long', 'map', 'max', 'min', 'object', 'oct', 'open', 'ord', 'pow',
'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'round',
'setattr', 'slice', 'staticmethod', 'str', 'super', 'tuple', 'type', 'unichr',
'unicode', 'vars', 'xrange', 'zip']

dir() 函数适用于所有对象类型,包括字符串、整数、列表、元组、字典、函数、定制类、类实例和类方法。让我们将 dir() 应用于字符串对象,并观察 Python 返回什么。如您所见,即使简单的 Python 字符串也有许多属性:

清单 21. 字符串属性
>>> dir('this is a string')
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__',
'__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__',
'__hash__', '__init__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
'__new__', '__reduce__', '__repr__', '__rmul__', '__setattr__', '__str__',
'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs',
'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace',
'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'replace', 'rfind',
'rindex', 'rjust', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',
'swapcase', 'title', 'translate', 'upper', 'zfill']

自己尝试下列示例以观察它们返回什么。注:# 字符标记注释的开始。Python 将忽略从注释开始部分到该行结束之间的所有内容:

清单 22. 将 dir() 运用于其它对象
dir(42)   # Integer (and the meaning of life)
dir([])   # List (an empty list, actually)
dir(())   # Tuple (also empty)
dir({})   # Dictionary (ditto)
dir(dir)  # Function (functions are also objects)

为了说明 Python 自省能力的动态本质,让我们研究将 dir() 运用于定制类和一些类实例的示例。我们将以交互方式定义自己的类,创建一些类的实例,仅向其中一个实例添加唯一的属性,并观察 Python 能否一直保存所有这些。以下是结果:

清单 23. 将 dir() 运用于定制类、类实例和属性
>>> class Person(object):
...     """Person class."""
...     def __init__(self, name, age):
...         self.name = name
...         self.age = age
...     def intro(self):
...         """Return an introduction."""
...         return "Hello, my name is %s and I'm %s." % (self.name, self.age)
...
>>> bob = Person("Robert", 35)   # Create a Person instance
>>> joe = Person("Joseph", 17)   # Create another
>>> joe.sport = "football"       # Assign a new attribute to one instance
>>> dir(Person)      # Attributes of the Person class
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__repr__',
'__setattr__', '__str__', '__weakref__', 'intro']
>>> dir(bob)         # Attributes of bob
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__repr__',
'__setattr__', '__str__', '__weakref__', 'age', 'intro', 'name']
>>> dir(joe)         # Note that joe has an additional attribute
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__repr__',
'__setattr__', '__str__', '__weakref__', 'age', 'intro', 'name', 'sport']
>>> bob.intro()      # Calling bob's intro method
"Hello, my name is Robert and I'm 35."
>>> dir(bob.intro)   # Attributes of the intro method
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__get__',
'__getattribute__', '__hash__', '__init__', '__new__', '__reduce__',
'__repr__', '__setattr__', '__str__', 'im_class', 'im_func', 'im_self']

文档字符串

在许多 dir() 示例中,您可能会注意到的一个属性是 __doc__ 属性。这个属性是一个字符串,它包含了描述对象的注释。Python 称之为文档字符串或 docstring,以下是其工作原理。如果模块、类、方法或函数定义的第一条语句是字符串,那么该字符串会作为对象的 __doc__ 属性与该对象关联起来。例如,看一下 __builtins__ 对象的文档字符串。因为文档字符串通常包含嵌入的换行 \n,我们将使用 Python 的 print 语句,以便输出更易于阅读:

清单 24. 模块文档字符串
>>> print __builtins__.__doc__   # Module docstring
Built-in functions, exceptions, and other objects.
Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices.

Python 甚至再次维持了在 Python shell 中以交互方式定义的类和方法上的文档字符串。让我们研究 Person 类及其 intro 方法的文档字符串:

清单 25. 类和方法文档字符串
>>> Person.__doc__         # Class docstring
'Person class.'
>>> Person.intro.__doc__   # Class method docstring
'Return an introduction.'

因为文档字符串提供了如此有价值的信息,所以许多 Python 开发环境都有自动显示对象的文档字符串的方法。让我们再看一个 dir() 函数的文档字符串:

清单 26. 函数文档字符串
>>> print dir.__doc__   # Function docstring
dir([object]) -> list of strings
Return an alphabetized list of names comprising (some of) the attributes
of the given object, and of attributes reachable from it:
No argument:  the names in the current scope.
Module object:  the module attributes.
Type or class object:  its attributes, and recursively the attributes of
    its bases.
Otherwise:  its attributes, its class's attributes, and recursively the
    attributes of its class's base classes.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值