python 自省_Python自省指南

python 自省

什么是内省?

在日常生活中,自省是自我检查的行为。 内省是指对自己的思想,感觉,动机和行为的检查。 伟大的哲学家苏格拉底(Socrates)将一生的大部分时间都花在自我检查上,鼓励他的雅典人也这样做。 他甚至声称,对他来说,“未经检查的生活是不值得生活的”。 (请参阅相关主题的链接以获得更多关于苏格拉底。)

在计算机程序设计中,自省是指检查某事物以确定它是什么,它知道什么以及它能够做什么的能力。 自省为程序员提供了很大的灵活性和控制力。 使用支持自省的编程语言后,您可能会类似地感到“未经检查的对象不值得实例化”。

本文介绍了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>

现在,我们似乎越来越近了。 让我们在帮助提示下输入keywords

清单4.寻求关键字帮助
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() ,我们会看到一条消息和一些说明,然后是帮助提示。 在提示符下,我们输入了keywords ,并显示了Python关键字列表。 得到问题的答案后,我们退出帮助实用程序,看到简短的告别消息,然后返回到Python提示符。

从该示例中可以看到,Python的联机帮助实用程序显示有关各种主题或特定对象的信息。 help实用程序非常有用,并且确实利用了Python的自省功能。 但是,仅仅使用帮助并不能揭示帮助如何获取其信息。 并且由于本文的目的是揭示Python的所有自省秘密,因此我们需要快速超越help实用工具。

在离开帮助之前,让我们使用它来获取可用模块的列表。 模块只是包含名称以.py结尾的Python代码的文本文件。 如果我们在Python提示符下键入help('modules') ,或在帮助提示符下输入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外壳,如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'>}

关键字模块

让我们回到有关Python关键字的问题。 即使帮助向我们显示了关键字列表,事实证明,帮助的某些信息也是经过硬编码的。 关键字列表恰好是硬编码的,毕竟不是很内省。 让我们看看是否可以直接从Python标准库中的模块之一获取此信息。 如果我们在Python提示符下键入help('modules keywords') ,则会看到以下内容:

清单14.在带有关键字的模块上寻求帮助
>>> 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.关键字模块的关键字列表
>>> 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.关键字模块的属性
>>> 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无需执行任何操作即可识别内置函数。 现在我们看到这个名称__builtins__通过调用dir()返回的。 也许这里有联系。 让我们在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.

询问Python对象

我们已经多次提到“对象”一词,但还没有真正定义它。 编程环境中的对象很像现实世界中的对象。 真实物体具有一定的形状,大小,重量和其他特征。 真实对象能够响应其环境,与其他对象交互或执行任务。 计算机对象尝试对现实世界中的对象进行建模,包括抽象对象,如文档,进度表和业务流程。

像现实世界中的对象一样,几个计算机对象可以共享共同的特征,同时保持自己的微小变化。 想一想在书店里看到的书。 一本书的每本物理副本都可能有污迹,几页撕裂或唯一的标识号。 而且,尽管每本书都是唯一的对象,但每本书标题相同,却只是原始模板的一个实例,并且保留了原始模板的大部分特征。

面向对象的类和类实例也是如此。 例如,每个Python字符串都具有dir()函数揭示的属性。 在前面的示例中,我们定义了自己的Person类,该类充当创建个人Person实例的模板,每个实例都有自己的名称和年龄值,同时具有自我介绍的能力。 那是面向对象的。

用计算机术语来说,对象就是具有身份和值,具有某种类型,具有某些特征并以某种方式运行的事物。 对象从一个或多个父类继承许多属性。 除了关键字和特殊符号(如+-***/%<>等运算符)之外,Python中的所有对象都是对象。 Python附带了丰富的对象类型集:字符串,整数,浮点数,列表,元组,字典,函数,类,类实例,模块,文件等。

当您有一个任意对象(也许是作为参数传递给函数的对象)时,您可能想了解有关该对象的一些知识。 在本节中,我们将向您展示如何获取Python对象来回答以下问题:

  • 你叫什么名字?
  • 你是什​​么样的物体?
  • 你知道什么?
  • 你能做什么?
  • 你的父母是谁?

名称

并非所有对象都有名称,但是对于所有对象都有名称,名称存储在其__name__属性中。 请注意,名称是从对象派生的,而不是引用对象的变量。 以下示例突出了这一区别:

清单27.名称是什么?
$ 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.
>>> dir()                # The dir() function
['__builtins__', '__doc__', '__name__']
>>> directory = dir      # Create a new variable
>>> directory()          # Works just like the original object
['__builtins__', '__doc__', '__name__', 'directory']
>>> dir.__name__         # What's your name?
'dir'
>>> directory.__name__   # My name is the same
'dir'
>>> __name__             # And now for something completely different
'__main__'

模块有名称,Python解释器本身被认为是顶级模块或主模块。 当您以交互方式运行Python时,会为本地__name__变量分配一个'__main__'值。 同样,当您从命令行执行Python模块,而不是将其导入另一个模块时,其__name__属性将被分配一个值'__main__' ,而不是模块的实际名称。 通过这种方式,模块可以查看自己的__name__值来自己确定如何使用它们,无论是作为对另一个程序的支持还是作为从命令行执行的主要应用程序。 因此,以下习语在Python模块中非常普遍:

清单28.测试执行或导入
if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.

类型

type()函数可帮助我们确定对象是字符串还是整数或其他类型的对象。 它通过返回一个类型对象来做到这一点,该对象可以与types模块中定义的types进行比较:

清单29.我是您的类型吗?
>>> import types
>>> print types.__doc__
Define names for all type symbols known in the standard interpreter.

Types that are part of optional modules (e.g. array) are not listed.

>>> dir(types)
['BufferType', 'BuiltinFunctionType', 'BuiltinMethodType', 'ClassType',
'CodeType', 'ComplexType', 'DictProxyType', 'DictType', 'DictionaryType',
'EllipsisType', 'FileType', 'FloatType', 'FrameType', 'FunctionType',
'GeneratorType', 'InstanceType', 'IntType', 'LambdaType', 'ListType',
'LongType', 'MethodType', 'ModuleType', 'NoneType', 'ObjectType', 'SliceType',
'StringType', 'StringTypes', 'TracebackType', 'TupleType', 'TypeType',
'UnboundMethodType', 'UnicodeType', 'XRangeType', '__builtins__', '__doc__',
'__file__', '__name__']
>>> s = 'a sample string'
>>> type(s)
<type 'str'>
>>> if type(s) is types.StringType: print "s is a string"
...
s is a string
>>> type(42)
<type 'int'>
>>> type([])
<type 'list'>
>>> type({})
<type 'dict'>
>>> type(dir)
<type 'builtin_function_or_method'>

身分识别

前面我们说过,每个对象都有一个标识,一个类型和一个值。 需要注意的重要一点是,多个变量可以引用完全相同的对象,同样,变量可以引用外观相似(具有相同类型和值)但具有不同标识的对象。 当对对象进行更改(例如将项目追加到列表)时,对象身份的这一概念特别重要,如下面的示例所示,其中blistclist变量都引用同一列表对象。 在示例中可以看到, id()函数返回任何给定对象的唯一标识符:

清单30. Bourne ...
>>> print id.__doc__
id(object) -> integer

Return the identity of an object.  This is guaranteed to be unique among
simultaneously existing objects.  (Hint: it's the object's memory address.)
>>> alist = [1, 2, 3]
>>> blist = [1, 2, 3]
>>> clist = blist
>>> clist
[1, 2, 3]
>>> blist
[1, 2, 3]
>>> alist
[1, 2, 3]
>>> id(alist)
145381412
>>> id(blist)
140406428
>>> id(clist)
140406428
>>> alist is blist    # Returns 1 if True, 0 if False
0
>>> blist is clist    # Ditto
1
>>> clist.append(4)   # Add an item to the end of the list
>>> clist
[1, 2, 3, 4]
>>> blist             # Same, because they both point to the same object
[1, 2, 3, 4]
>>> alist             # This one only looked the same initially
[1, 2, 3]

属性

我们已经看到对象具有属性,并且dir()函数将返回这些属性的列表。 但是,有时候,我们只是想测试一个或多个属性的存在。 而且,如果对象具有所讨论的属性,我们通常希望检索该属性。 这些任务由hasattr()getattr()函数处理,如本示例所示:

清单31.有一个属性; 获取属性
>>> print hasattr.__doc__
hasattr(object, name) -> Boolean

Return whether the object has an attribute with the given name.
(This is done by calling getattr(object, name) and catching exceptions.)
>>> print getattr.__doc__
getattr(object, name[, default]) -> value

Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
>>> hasattr(id, '__doc__')
1
>>> print getattr(id, '__doc__')
id(object) -> integer

Return the identity of an object.  This is guaranteed to be unique among
simultaneously existing objects.  (Hint: it's the object's memory address.)

可赎回

可以调用或调用代表潜在行为(功能和方法)的对象。 我们可以使用callable()函数测试对象的callable()性:

清单32.您能为我做点什么吗?
>>> print callable.__doc__
callable(object) -> Boolean

Return whether the object is callable (i.e., some kind of function).
Note that classes are callable, as are instances with a __call__() method.
>>> callable('a string')
0
>>> callable(dir)
1

执行个体

尽管type()函数为我们提供了对象的类型,但我们也可以使用isinstance()函数测试对象以确定它是特定类型的实例还是自定义类:

清单33.您是其中之一吗?
>>> print isinstance.__doc__
isinstance(object, class-or-type-or-tuple) -> Boolean

Return whether an object is an instance of a class or of a subclass thereof.
With a type as second argument, return whether that is the object's type.
The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for
isinstance(x, A) or isinstance(x, B) or ... (etc.).
>>> isinstance(42, str)
0
>>> isinstance('a string', int)
0
>>> isinstance(42, int)
1
>>> isinstance('a string', str)
1

子类

前面我们提到过,自定义类的实例从该类继承其属性。 在类级别,可以用另一个类来定义一个类,并且同样会以分层方式继承属性。 Python甚至支持多重继承,这意味着可以根据一个以上的父类定义一个继承的类,并且可以从多个父类继承一个单独的类。 issubclass()函数使我们能够确定一个类是否继承自另一个类:

清单34.您是我的母亲吗?
>>> print issubclass.__doc__
issubclass(C, B) -> Boolean

Return whether class C is a subclass (i.e., a derived class) of class B.
>>> class SuperHero(Person):   # SuperHero inherits from Person...
...     def intro(self):       # but with a new SuperHero intro
...         """Return an introduction."""
...         return "Hello, I'm SuperHero %s and I'm %s." % (self.name, self.age)
...
>>> issubclass(SuperHero, Person)
1
>>> issubclass(Person, SuperHero)
0
>>>

审讯时间

让我们总结一下上一节中介绍的几种自省技术。 为此,我们将定义我们自己的函数interrogate() ,该函数打印有关传递给它的任何对象的各种信息。 这是代码,然后是几个用法示例:

清单35.没有人期望
>>> def interrogate(item):
...     """Print useful information about item."""
...     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
...
>>> interrogate('a string')     # String object
CLASS:    str
ID:       141462040
TYPE:     <type 'str'>
VALUE:    'a string'
CALLABLE: No
DOC:      str(object) -> string
>>> interrogate(42)             # Integer object
CLASS:    int
ID:       135447416
TYPE:     <type 'int'>
VALUE:    42
CALLABLE: No
DOC:      int(x[, base]) -> integer
>>> interrogate(interrogate)    # User-defined function object
NAME:     interrogate
CLASS:    function
ID:       141444892
TYPE:     <type 'function'>
VALUE:    <function interrogate at 0x86e471c>
CALLABLE: Yes
DOC:      Print useful information about item.

正如您在上一个示例中看到的那样,我们的interrogate()函数甚至可以对其自身起作用。 你不能比这更自省。

结论

谁知道内省会如此简单,如此有益呢? 但是,我在这里必须谨慎行事:不要将内省的结果误认为是智慧。 经验丰富的Python程序员知道,总是会有更多他们不知道的东西,因此根本就不明智。 编程行为产生的问题多于答案。 正如我们今天在这里看到的那样,Python的唯一好处是它确实回答了人们的问题。 对于我而言,不需要因为帮助您了解Python必须提供的这些东西而向我补偿。 用Python编程是它自己的奖励。 我向同胞们的要求是免费的餐点,费用由公共承担。


翻译自: https://www.ibm.com/developerworks/opensource/library/l-pyint/index.html

python 自省

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值