天天看點

python 幫助文檔、自我解釋

現在讓我們以互動方式使用 Python 來開始研究。當我們從指令行啟動 Python 時,就進入了 Python shell,在這裡可以輸入 Python 代碼,而且立刻會從 Python 解釋器獲得響應。

清單 1. 以互動方式啟動 Python 解釋器
Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
[GCC 7.3.0] 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                if                  print
as                  else                import              raise
assert              except              in                  return
break               exec                is                  try
class               finally             lambda              while
continue            for                 not                 with
def                 from                or                  yield
del                 global              pass     

`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 ,會看到類似于下面的資訊:

清單 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()

 傳回目前作用域中的名稱。請注意,因為我們先前導入了 

keyword

 和 

sys

 ,是以它們出現在清單中。導入子產品将把該子產品的名稱添加到目前作用域:

清單 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.`
           

檢查 Python 對象

我們好幾次提到了“對象(object)”這個詞,但一直沒有真正定義它。程式設計環境中的對象很象現實世界中的對象。實際的對象有一定的形狀、大小、重量和其它特征。實際的對象還能夠對其環境進行響應、與其它對象互動或執行任務。計算機中的對象試圖模拟我們身邊現實世界中的對象,包括象文檔、日程表和業務過程這樣的抽象對象。

類似于實際的對象,幾個計算機對象可能共享共同的特征,同時保持它們自己相對較小的變異特征。想一想您在書店中看到的書籍。書籍的每個實體副本都可能有污迹、幾張破損的書頁或唯一的辨別号。盡管每本書都是唯一的對象,但都擁有相同标題的每本書都隻是原始模闆的執行個體,并保留了原始模闆的大多數特征。

對于面向對象的類和類執行個體也是如此。例如,可以看到每個 Python 字元串都被賦予了一些屬性, 

dir()

 函數揭示了這些屬性。在前一個示例中,我們定義了自己的 

Person

 類,它擔任建立個别 Person 執行個體的模闆,每個執行個體都有自己的 name 和 age 值,同時共享自我介紹的能力。這就是面向對象。

于是在計算機術語中,對象是擁有辨別和值的事物,屬于特定類型、具有特定特征和以特定方式執行操作。并且,對象從一個或多個父類繼承了它們的許多屬性。除了關鍵字和特殊符号(象運算符,如 

+

 、 

-

*

**

/

%

<

>

 等)外,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

 子產品中定義的類型相比較:

清單 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'>`
           

辨別

先前我們說過,每個對象都有辨別、類型和值。值得注意的是,可能有多個變量引用同一對象,同樣地,變量可以引用看起來相似(有相同的類型和值),但擁有截然不同辨別的多個對象。當更改對象時(如将某一項添加到清單),這種關于對象辨別的概念尤其重要,如在下面的示例中, 

blist

clist

 變量引用同一個清單對象。正如您在示例中所見, 

id()

 函數給任何給定對象傳回唯一的辨別符:

清單 30. 目的地……
`>>> 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()

 函數測試對象的可調用性:

清單 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()

 函數甚至可以應用于它本身。您沒有再比它更具“自省性”的工具了。