亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標(biāo)題: Python 指南 [打印本頁(yè)]

作者: mq110    時(shí)間: 2005-05-31 16:43
標(biāo)題: Python 指南
前言

目錄

1. 開(kāi)胃菜

2. 使用Python解釋器

2.1 調(diào)用解釋器

2.1.1 傳遞參數(shù)

2.1.2 交互模式

2.2 解釋器及其工作模式

2.2.1 錯(cuò)誤處理

2.2.2 執(zhí)行 Python 腳本

2.2.3 源程序編碼

2.2.4 交互環(huán)境的啟動(dòng)文件

3.初步認(rèn)識(shí) Python

3.1 像使用計(jì)算器一樣使用Python

3.1.1 數(shù)值

3.1.2 字符串

3.1.3 Unicode 字符串

3.1.4 鏈表

3.2 開(kāi)始編程

4. 流程控制

4.1 if 語(yǔ)法

4.2 for 語(yǔ)法

4.3 range() 函數(shù)

4.4 break 和 continue 語(yǔ)法以及 else 子句 在循環(huán)中的用法

4.5 pass 語(yǔ)法

4.6 定義函數(shù)

4.7 定義函數(shù)的進(jìn)一步知識(shí)

4.7.1 定義參數(shù)變量

4.7.2 參數(shù)關(guān)鍵字

4.7.3 可變參數(shù)表

4.7.4 Lambda 形式

4.7.5 文檔字符串

5. 數(shù)據(jù)結(jié)構(gòu)

5.1 深入鏈表

5.1.1 將鏈表作為堆棧來(lái)使用

5.1.2 將鏈表作為隊(duì)列來(lái)使用

5.1.3 函數(shù)化的編程工具

5.1.4 鏈表的內(nèi)含(Comprehensions)

5.2 del 語(yǔ)法

5.3 Tuples 和 Sequences

5.4 字典(Dictionaries)

5.5 循環(huán)技巧

5.6 深入條件控制

5.7 Sequences 和其它類型的比較

6. 模塊

6.1 深入模塊

6.1.1 模塊搜索路徑

6.1.2 “編譯” Python 文件

6.2 標(biāo)準(zhǔn)模塊

6.3 dir() 函數(shù)

6.4 包

6.4.1 從包中導(dǎo)入所有內(nèi)容(import * )

6.4.2 隱式包引用

6.4.3 包中的多重路徑

7. 輸入和輸出

7.1 格式化輸出

7.2 讀寫文件

7.2.1 文件對(duì)象的方法

7.2.2 pickle 模塊

8. 錯(cuò)誤和異常

8.1 語(yǔ)法 Errors

8.2 異常

8.3 捕獲異常

8.4 釋放異常

8.5 用戶自定義異常

8.6 定義 Clean-up Actions

9. 類

9.1 有關(guān)術(shù)語(yǔ)的話題

9.2 Python 的作用域和命名空間

9.3 初識(shí)類

9.3.1 類定義語(yǔ)法

9.3.2 類對(duì)象

9.3.3 實(shí)例對(duì)象

9.3.4 方法對(duì)象

9.4 一些說(shuō)明

9.5 繼承

9.5.1 多繼承

9.6 私有變量

9.7 補(bǔ)充

9.8 異常也是類

9.9 迭代子(Iterators)

9.10 發(fā)生器(Generators)

10. 接下來(lái)?

A. 交互式編輯和歷史回溯

A.1 行編輯

A.2 歷史回溯

A.3 快捷鍵綁定

A.4 注釋

B. 浮點(diǎn)計(jì)算:?jiǎn)栴}與極限

B.1 表達(dá)錯(cuò)誤

C. 歷史和授權(quán)

C.1 本軟件的歷史

C.2 修改和使用Python的條件(Terms and conditions for accessing or otherwise using Python)

關(guān)于本文檔
作者: mq110    時(shí)間: 2005-05-31 16:44
標(biāo)題: Python 指南
前言
Copyright & 2001, 2002, 2003 Python Software Foundation. All rights reserved.

Copyright & 2000 BeOpen.com. All rights reserved.

Copyright & 1995-2000 Corporation for National Research Initiatives. All rights reserved.

Copyright & 1991-1995 Stichting Mathematisch Centrum. All rights reserved.

See the end of this document for complete license and permissions information.

概要:
Python 是一種容易學(xué)習(xí)的強(qiáng)大語(yǔ)言。它包括了高效的高級(jí)數(shù)據(jù)結(jié)構(gòu),提供了一個(gè)簡(jiǎn)單但很有有效的方式以便進(jìn)行面向?qū)ο缶幊獭ython 優(yōu)雅的語(yǔ)法,動(dòng)態(tài)數(shù)據(jù)類型,以及它的解釋器,使其成為了大多數(shù)平臺(tái)上應(yīng)用于各領(lǐng)域理想的腳本語(yǔ)言以及開(kāi)發(fā)環(huán)境。

Python解釋器及其擴(kuò)展標(biāo)準(zhǔn)庫(kù)的源碼和編譯版本可以從Python的Web站點(diǎn)http://www.python.org/及其所有鏡像站上免費(fèi)獲得,并且可以自由發(fā)布。該站點(diǎn)上也提供了Python的一些第三方模塊,程序,工具,以及附加的文檔。

Python的解釋器很容易通過(guò)C或C++(或者其它可以由C來(lái)調(diào)用的語(yǔ)言)來(lái)實(shí)現(xiàn)功能和數(shù)據(jù)結(jié)構(gòu)的擴(kuò)展。因些Python 也很適于做為定制應(yīng)用的一種擴(kuò)展語(yǔ)言。

這個(gè)手冊(cè)介紹了一些Python語(yǔ)言及其系統(tǒng)的基本知識(shí)與根念。這有助于對(duì)Python有一個(gè)基本的認(rèn)識(shí),當(dāng)然所有的例子都包括在里面了,所以這本手冊(cè)很適合離線閱讀。

需要有關(guān)標(biāo)準(zhǔn)對(duì)象和模塊的詳細(xì)介紹的話,請(qǐng)查詢Python 程序庫(kù)參考手冊(cè) 文檔。Python 參考手冊(cè) 提供了更多的關(guān)于語(yǔ)言方面的正式說(shuō)明。需要編寫C或C++擴(kuò)展,請(qǐng)閱讀 Python 解釋器的擴(kuò)展和集成 以及Python/C API 參考手冊(cè)。這幾本書(shū)涵蓋了各個(gè)深度上的Python知識(shí)。

本手冊(cè)不會(huì)涵蓋Python的所有功能,也不會(huì)去解釋所用到的所有相關(guān)的知識(shí)。相反,它介紹了許多Python中最引人注目的功能,這會(huì)對(duì)讀者掌握這門語(yǔ)言的風(fēng)格大有幫助。讀過(guò)它后,你應(yīng)該可以閱讀和編寫Python模塊和程序了,接下來(lái)你可以從Python 庫(kù)參考手冊(cè)中進(jìn)一步學(xué)習(xí)Python復(fù)雜多變的庫(kù)和模塊了。
作者: mq110    時(shí)間: 2005-05-31 16:44
標(biāo)題: Python 指南
1. 開(kāi)胃菜
如果你寫過(guò)大規(guī)模的Shell腳本,應(yīng)該會(huì)有過(guò)這樣的體會(huì):你還非常想再加一些別的功能進(jìn)去,但它已經(jīng)太大、太慢、太復(fù)雜了;或者這個(gè)功能需要調(diào)用一個(gè)系統(tǒng)函數(shù),或者它只適合通過(guò)C來(lái)調(diào)用……通常這些問(wèn)題還不足以嚴(yán)肅到需要用C重寫這個(gè)Shell;可能這個(gè)功能需要一些類似變長(zhǎng)字符串或其它一些在Shell腳本中很容易找到的數(shù)據(jù)類型(比如文件名的有序列表),但它們用C來(lái)實(shí)現(xiàn)就要做大量的工作,或者,你對(duì)C還不是很熟悉。

另一種情況:可能你需要使用幾個(gè)C庫(kù)來(lái)工作,通常C的編寫/編譯/測(cè)試/重編譯周期太慢。你需要盡快的開(kāi)發(fā)軟件。也許你需要寫一個(gè)使用擴(kuò)展語(yǔ)言的程序,但不想設(shè)計(jì)一個(gè)語(yǔ)言,并為此編寫調(diào)試一個(gè)解釋器,然后再把它集成進(jìn)你的程序。

遇到以上情況,Python可能就是你要找的語(yǔ)言。Python很容易上手,但它是一門真正的編程語(yǔ)言,提供了比Shell多的多的結(jié)構(gòu),支持大型程序。另一方面,它提供了比C更多的錯(cuò)誤檢查,并且,做為一門高級(jí)語(yǔ)言,它擁有內(nèi)置的高級(jí)數(shù)據(jù)類型,例如可變數(shù)組和字典,如果通過(guò)C來(lái)實(shí)現(xiàn)的話,這些工作可能讓你大干上幾天的時(shí)間。因?yàn)閾碛懈嗟耐ㄓ脭?shù)據(jù)類型,Python適合比Awk甚至Perl更廣泛的問(wèn)題領(lǐng)域,在其它的很多領(lǐng)域,Python至少比別的語(yǔ)言要易用得多。

Python可以讓你把自己的程序分隔成不同的模塊,這樣就可以在其它的Python程序中重用。這樣你就可以讓自己的程序基于一個(gè)很大的標(biāo)準(zhǔn)模塊集或者用它們做為示例來(lái)學(xué)習(xí)Python編程。Python中集成了一些類似文件I/O,系統(tǒng)調(diào)用,sockets,甚至像Tk這樣的用戶圖形接口。

Python是一門解釋型語(yǔ)言,因?yàn)椴恍枰幾g和鏈接的時(shí)間,它可以幫你省下一些開(kāi)發(fā)時(shí)間。解釋器可以交互式使用,這樣就可以很方便的測(cè)試語(yǔ)言中的各種功能,以便于編寫發(fā)布用的程序,或者進(jìn)行自下而上的開(kāi)發(fā)。還可以當(dāng)它是一個(gè)隨手可用的計(jì)算器。

Python可以寫出很緊湊和可讀性很強(qiáng)的程序。用Python寫的程序通常比同樣的C或C++程序要短得多,這是因?yàn)橐韵聨讉(gè)原因:

高級(jí)數(shù)據(jù)結(jié)構(gòu)使你可以在一個(gè)單獨(dú)的語(yǔ)句中表達(dá)出很復(fù)雜的操作;

語(yǔ)句的組織依賴于縮進(jìn)而不是begin/end塊;

不需要變量或參數(shù)聲明。

Python是可執(zhí)行的:如果你會(huì)用C語(yǔ)言寫程序,那就可以很容易的為解釋器添加新的集成模塊和功能,或者優(yōu)化瓶頸,使其達(dá)到最大速度,或者使Python能夠鏈接到所需的二進(jìn)制架構(gòu)上(比如某個(gè)專用的商業(yè)圖形庫(kù))。等你真正熟悉這一切了,你就可以把Python集成進(jìn)由C寫成的程序,把Python當(dāng)做這個(gè)程序的擴(kuò)展或命令行語(yǔ)言。

順便說(shuō)一下,這個(gè)語(yǔ)言的名字來(lái)源于BBC的“Monty Python's Flying Circus”節(jié)目,和兇猛的爬蟲(chóng)沒(méi)有任何關(guān)系。在文檔中引用Monty Python典故不僅是允許的,而且還受到鼓勵(lì)!

現(xiàn)在你已經(jīng)了解了Python中所有激動(dòng)人心的東西,大概你想仔細(xì)的試試它了。學(xué)習(xí)一門語(yǔ)言最好的辦法就是使用它,你會(huì)很樂(lè)于這樣做。

下一節(jié)中,我們會(huì)很機(jī)械的說(shuō)明解釋器的用法。這沒(méi)有什么神秘的,不過(guò)有助于我們練習(xí)后面展示的例子。

本指南其它部分通過(guò)例子介紹了Python語(yǔ)言和系統(tǒng)的各種功能,開(kāi)始是簡(jiǎn)單表達(dá)式、語(yǔ)法和數(shù)據(jù)類型,接下來(lái)是函數(shù)和模塊,最后是諸如異常和自定義類這樣的高級(jí)內(nèi)容。
作者: mq110    時(shí)間: 2005-05-31 16:45
標(biāo)題: Python 指南
2. 使用Python解釋器
  
2.1 調(diào)用解釋器
通常Python的解釋器被安裝在目標(biāo)機(jī)器的 /usr/local/bin/python 目錄下;把 /usr/local/bin 目錄放進(jìn)你的UNIX Shell 的搜索路徑里,確保它可以通過(guò)輸入

python
來(lái)啟動(dòng)。因?yàn)榘惭b路徑是可選的,所以也有可能安裝在其它位置,你可以與安裝Python的用戶或系統(tǒng)管理員聯(lián)系。(例如,/usr/local/python就是一個(gè)很常見(jiàn)的選擇)

輸入一個(gè)文件結(jié)束符(UNIX上是Ctrl+D,Windwos上是Ctrl+Z)解釋器會(huì)以0值退出(就是說(shuō),沒(méi)有什么錯(cuò)誤,正常退出--譯者)。如果這沒(méi)有起作用,你可以輸入以下命令退出:“import sys; sys.exit()”。

解釋器的行編輯功能并不很復(fù)雜。裝在Unix上的解釋器可能會(huì)有GNU readline 庫(kù)支持,這樣就可以額外得到精巧的交互編輯和歷史記錄功能?赡軝z查命令行編輯器支持能力最方便的方式是在主提示符下輸入Ctrl+P。如果有嘟嘟聲(計(jì)算機(jī)揚(yáng)聲器),說(shuō)明你可以使用命令行編輯功能,從附錄 A 可以查到快捷鍵的介紹。如果什么也沒(méi)有發(fā)聲,或者P顯示了出來(lái),說(shuō)明命令行編輯功能不可用,你只有用退格鍵刪掉輸入的命令了。

解釋器的操作有些像Unix Shell:使用終端設(shè)備做為標(biāo)準(zhǔn)輸入來(lái)調(diào)用它時(shí),解釋器交互的解讀和執(zhí)行命令,通過(guò)文件名參數(shù)或以文件做為標(biāo)準(zhǔn)輸入設(shè)備時(shí),它從文件中解讀并執(zhí)行腳本。

啟動(dòng)解釋器的第三個(gè)方法是“python -c command [arg] ...”,這種方法可以在命令行中直接執(zhí)行語(yǔ)句,等同于Shell的 -c選項(xiàng)。因?yàn)镻ython語(yǔ)句通常會(huì)包括空格之類的特殊字符,所以最好把整個(gè)語(yǔ)句用雙引號(hào)包起來(lái)。

注意“python file”和“python <file”是有區(qū)別的。對(duì)于后一種情況,程序中類似于調(diào)用 input() 和raw_input()這樣的輸入請(qǐng)求,來(lái)自于確定的文件。因?yàn)樵诮馕銎鏖_(kāi)始執(zhí)行之前,文件已經(jīng)完全讀入,所以程序指向文件尾。在前一種情況(這通常是你需要的)它們從來(lái)自于任何聯(lián)接到Python解釋器的標(biāo)準(zhǔn)輸入,無(wú)論它們是文件還是其它設(shè)備。

使用腳本文件時(shí),經(jīng)常會(huì)運(yùn)行腳本然后進(jìn)入交互模式。這也可以通過(guò)在腳本之前加上-i參數(shù)來(lái)實(shí)現(xiàn)。(如果腳本來(lái)自標(biāo)準(zhǔn)輸入,就不能這樣運(yùn)行,與前一段提到的原因一樣。)

  
2.1.1 參數(shù)傳遞
調(diào)用解釋器時(shí),腳本名和附加參數(shù)之傳入一個(gè)名為sys.argv的字符串列表。沒(méi)有腳本和參數(shù)時(shí),它至少也有一個(gè)元素:sys.argv[0]此時(shí)為空字符串。腳本名指定為‘ - ’(表示標(biāo)準(zhǔn)輸入)時(shí),sys.argv[0]被設(shè)置為‘ - ’,使用 -c 指令時(shí),sys.argv[0]被設(shè)定為‘ -c ’。 -c 命令之后的參數(shù)不會(huì)被 Python 解釋器的選項(xiàng)處理機(jī)制所截獲,而是留在sys.argv 中,供腳本命令操作。

  
2.1.2 交互模式
從tty讀取命令時(shí),我們稱解釋器工作于交互模式。這種模式下它根據(jù)主提示符來(lái)執(zhí)行,主提示符通常標(biāo)識(shí)為三個(gè)大于號(hào)(“>;>;>; ”);繼續(xù)的部分被稱為從屬提示符,由三個(gè)點(diǎn)標(biāo)識(shí)(“... ”)。在第一行之前,解釋器打印歡迎信息、版本號(hào)和授權(quán)提示:

python
Python 2.3 (#1, Jul 30 2003, 23:22:59)
[GCC 3.2 20020927 (prerelease)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>;>;>;
輸入多行結(jié)構(gòu)時(shí)需要從屬提示符了,例如,下面這個(gè) if 語(yǔ)句:

>;>;>; the_world_is_flat = 1
>;>;>; if the_world_is_flat:
...     print "Be careful not to fall off!"
...
Be careful not to fall off!
  
2.2 解釋器及其環(huán)境
  
2.2.1 錯(cuò)誤處理
有錯(cuò)誤發(fā)生時(shí),解釋器打印一個(gè)錯(cuò)誤信息和棧跟蹤(監(jiān)視)器?。交互模式下,它返回主提示符,如果從文件輸入執(zhí)行,它在打印棧跟蹤器后以非零狀態(tài)退出。(異?梢杂蓆ry語(yǔ)句中的except子句來(lái)控制,這樣就不會(huì)出現(xiàn)上文中的錯(cuò)誤信息)有一些非常致命的錯(cuò)誤會(huì)導(dǎo)致非零狀態(tài)下退出,這由通常由內(nèi)部矛盾和內(nèi)存溢出造成。所有的錯(cuò)誤信息都寫入標(biāo)準(zhǔn)錯(cuò)誤流;命令中執(zhí)行的普通輸出寫入標(biāo)準(zhǔn)輸出。

在主提示符或附屬提示符輸入中斷符(通常是Control-C or DEL)就會(huì)取消當(dāng)前輸入,回到主命令行。2.1執(zhí)行命令時(shí)輸入一個(gè)中斷符會(huì)拋出一個(gè) KeyboardInterrupt 異常,它可以被try句截獲。

  
2.2.2 執(zhí)行Python腳本
BSD系統(tǒng)中,Python腳本可以像Shell腳本那樣直接執(zhí)行,只要在腳本文件開(kāi)頭寫一行命令,指定文件和模式:

#! /usr/bin/env python
(將用戶路徑通知解釋器) “#!”必須是文件的前兩個(gè)字符,在某些平臺(tái)上,第一行必須以Unix風(fēng)格的行結(jié)束符(“\n”)結(jié)束,不能用Mac(“\r”)或Windows(“\r\n”)的結(jié)束符。注意,“#”是Python中是行注釋的起始符。

腳本可以通過(guò) chmod 命令指定執(zhí)行模式和許可權(quán)。

$ chmod +x myscript.py
2.2.3 源程序編碼
Python的源文件可以通過(guò)編碼使用 ASCII 以外的字符集。 最好的做法是在 #! 行后面用一個(gè)特殊的注釋行來(lái)定義字符集。

# -*- coding: iso-8859-1 -*-
根據(jù)這個(gè)聲明,Python會(huì)將文件中的字符盡可能的從指定的編碼轉(zhuǎn)為Unicode,在本例中,這個(gè)字符集是 iso-8859-1 。在 Python 庫(kù)參考手冊(cè) 中可以找到可用的編碼列表(根據(jù)我的實(shí)驗(yàn),中文似乎只能用cp-936或utf-8,不直接支持GB,GBK,GB-18030或ISO-10646--譯者注)。

如果你的文件編輯器支持UTF-8格式,并且可以保存UTF-8標(biāo)記(aka BOM - Byte Order Mark),你可以用這個(gè)來(lái)代替編碼聲明(看來(lái)至少Jext還不支持這樣做,而Vim,我還沒(méi)找到它的編碼設(shè)置在哪里,還是老老實(shí)實(shí)的用注釋行指定源代碼的編碼吧--譯者注)。IDLE可以通過(guò)設(shè)定Options/General/Default Source Encoding/UTF-8 來(lái)支持它。需要注意的是舊版Python不支持這個(gè)標(biāo)記(Python 2.2或更早的版本),也同樣不能使操作系統(tǒng)支持#!文件。

使用UTF-8內(nèi)碼(無(wú)論是用標(biāo)記還是編碼聲明),我們可以在字符串和注釋中使用世界上的大部分語(yǔ)言。標(biāo)識(shí)符中不能使用非 ASCII 字符集。為了正確顯示所有的字符,你一定要在編輯器中將文件保存為UTF-8格式,而且要使用支持文件中所有字符的字體。

  
2.2.4 交互式環(huán)境的啟動(dòng)文件
使用Python解釋器的時(shí)候,我們可能需要在每次解釋器啟動(dòng)時(shí)執(zhí)行一些命令。你可以在一個(gè)文件中包含你想要執(zhí)行的命令,設(shè)定一個(gè)名為PYTHONSTARTUP 的環(huán)境變量來(lái)指定這個(gè)文件。這類似于Unix shell的.profile文件。

這個(gè)文件在交互會(huì)話期是只讀的,當(dāng)Python從腳本中解讀文件或以終端做為外部命令源時(shí)則不會(huì)如此(盡管它們的行為很像是處在交互會(huì)話期。)它與解釋器執(zhí)行的命令處在同一個(gè)命名空間,所以由它定義或引用的一切可以在解釋器中不受限制的使用。你也可以在這個(gè)文件中改變sys.ps1和sys.ps2指令。

如果你想要在當(dāng)前目錄中執(zhí)行附加的啟動(dòng)文件,你可以在全局啟動(dòng)文件中加入類似以下的代碼:“if os.path.isfile('.pythonrc.py'): execfile('.pythonrc.py')”。 如果你想要在某個(gè)腳本中使用啟動(dòng)文件,必須要在腳本中寫入這樣的語(yǔ)句:

import os
filename = os.environ.get('PYTHONSTARTUP')
if filename and os.path.isfile(filename):
    execfile(filename)
作者: mq110    時(shí)間: 2005-05-31 16:45
標(biāo)題: Python 指南
3. Python的非正式介紹
在后面的例子中,區(qū)分輸入和輸出的方法是看是否有提示符(“>;>;>; ”和“.. ”):想要重復(fù)這些例子的話,你就要在提示符顯示后輸入所有的一切;沒(méi)有以提示符開(kāi)始的行,是解釋器輸出的信息。需要注意的是示例中的從屬提示符用于多行命令的結(jié)束,它表示你需要輸入一個(gè)空行。

本手冊(cè)中的很多示例都包括注釋,甚至有一些在交互提示符中折行。Python中的注釋以符號(hào)“#”起始,一直到當(dāng)前行的結(jié)尾。注釋可能出現(xiàn)在一行的開(kāi)始,也可能跟在空格或程序代碼之后,但不會(huì)出現(xiàn)在字符串中,字符串中的#號(hào)只代表#號(hào)。

示例:

# this is the first comment
SPAM = 1                 # and this is the second comment
                         # ... and now a third!
STRING = "# This is not a comment."
  
3.1 初步認(rèn)識(shí)Python
讓我們?cè)囼?yàn)一些簡(jiǎn)單的Python命令。啟動(dòng)解釋器然后等待主提示符“>;>;>; ”出現(xiàn)(這用不了太久)。

  
3.1.1 數(shù)值
解釋器的行為就像是一個(gè)計(jì)算器。你可以向它輸入一個(gè)表達(dá)式,它會(huì)返回結(jié)果。表達(dá)式的語(yǔ)法簡(jiǎn)明易懂:+,-,*,/和大多數(shù)語(yǔ)言中的用法一樣(比如C或Pascal),括號(hào)用于分組。例如:

>;>;>; 2+2
4
>;>;>; # This is a comment
... 2+2
4
>;>;>; 2+2  # and a comment on the same line as code
4
>;>;>; (50-5*6)/4
5
>;>;>; # Integer division returns the floor:
... 7/3
2
>;>;>; 7/-3
-3
像c一樣,等號(hào)(“=”)用于給變量賦值。被分配的值是只讀的。

>;>;>; width = 20
>;>;>; height = 5*9
>;>;>; width * height
900
同一個(gè)值可以同時(shí)賦給幾個(gè)變量:

>;>;>; x = y = z = 0  # Zero x, y and z
>;>;>; x
0
>;>;>; y
0
>;>;>; z
0
Python完全支持浮點(diǎn)數(shù),不同類型的操作數(shù)混在一起時(shí),操作符會(huì)把整型轉(zhuǎn)化為浮點(diǎn)數(shù)。

>;>;>; 3 * 3.75 / 1.5
7.5
>;>;>; 7.0 / 2
3.5
復(fù)數(shù)也同樣得到了支持,虛部由一個(gè)后綴“j”或者“J”來(lái)表示。帶有非零實(shí)部的復(fù)數(shù)記為“(real+imagj)”,或者也可以通過(guò)“complex(real, imag)”函數(shù)創(chuàng)建。

>;>;>; 1j * 1J
(-1+0j)
>;>;>; 1j * complex(0,1)
(-1+0j)
>;>;>; 3+1j*3
(3+3j)
>;>;>; (3+1j)*3
(9+3j)
>;>;>; (1+2j)/(1+1j)
(1.5+0.5j)
復(fù)數(shù)總是由實(shí)部和虛部?jī)刹糠指↑c(diǎn)數(shù)來(lái)表示?赡軓 z.real 和 z.imag 得到復(fù)數(shù)z的實(shí)部和虛部。

>;>;>; a=1.5+0.5j
>;>;>; a.real
1.5
>;>;>; a.imag
0.5
用于向浮點(diǎn)數(shù)和整型轉(zhuǎn)化的函數(shù)(float(), int() 和 long())不能對(duì)復(fù)數(shù)起作用--沒(méi)有什么方法可以將復(fù)數(shù)轉(zhuǎn)化為實(shí)數(shù)?梢允褂胊bs(z)取得它的模,也可以通過(guò)z.real得到它的實(shí)部。

>;>;>; a=3.0+4.0j
>;>;>; float(a)
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
TypeError: can't convert complex to float; use e.g. abs(z)
>;>;>; a.real
3.0
>;>;>; a.imag
4.0
>;>;>; abs(a)  # sqrt(a.real**2 + a.imag**2)
5.0
>;>;>;
交互模式下,最近一次表達(dá)式輸出保存在_變量中。這意味著把Python當(dāng)做桌面計(jì)算器使用時(shí),它可以更容易的進(jìn)行連續(xù)計(jì)算,例如:

>;>;>; tax = 12.5 / 100
>;>;>; price = 100.50
>;>;>; price * tax
12.5625
>;>;>; price + _
113.0625
>;>;>; round(_, 2)
113.06
>;>;>;
這個(gè)變量對(duì)于用戶來(lái)說(shuō)是只讀的。不要試圖去給它賦值--由于Python的語(yǔ)法效果,你只會(huì)創(chuàng)建一個(gè)同名的局部變量覆蓋它。

  
3.1.2 字符串
除了數(shù)值,Python還可以通過(guò)幾種不同的方法操作字符串。字符串用單引號(hào)或雙引號(hào)標(biāo)識(shí):

>;>;>; 'spam eggs'
'spam eggs'
>;>;>; 'doesn\'t'
"doesn't"
>;>;>; "doesn't"
"doesn't"
>;>;>; '"Yes," he said.'
'"Yes," he said.'
>;>;>; "\"Yes,\" he said."
'"Yes," he said.'
>;>;>; '"Isn\'t," she said.'
'"Isn\'t," she said.'
字符串可以通過(guò)幾種方式分行?梢栽谛屑臃葱备茏鰹槔^續(xù)符,這表示下一行是當(dāng)前行的邏輯沿續(xù)。

hello = "This is a rather long string containing\n\
several lines of text just as you would do in C.\n\
    Note that whitespace at the beginning of the line is\
significant."

print hello
注意換行用 \n 來(lái)表示;反斜杠后面的新行標(biāo)識(shí)(newline,縮寫“n”)會(huì)轉(zhuǎn)換為換行符,示例會(huì)按如下格式打印:

This is a rather long string containing
several lines of text just as you would do in C.
    Note that whitespace at the beginning of the line is significant.
然而,如果我們創(chuàng)建一個(gè)“raw”行,\n序列就不會(huì)轉(zhuǎn)為換行,示例源碼最后的反斜杠和換行符n都會(huì)做為字符串中的數(shù)據(jù)處理。如下所示:

hello = r"This is a rather long string containing\n\
several lines of text much as you would do in C."

print hello
會(huì)打印為:

This is a rather long string containing\n\
several lines of text much as you would do in C.
或者,字符串可以用一對(duì)三重引號(hào)”””或'''來(lái)標(biāo)識(shí)。三重引號(hào)中的字符串在行尾不需要換行標(biāo)記,所有的格式都會(huì)包括在字符串中。

print """
Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
"""
produces the following output:

Usage: thingy [OPTIONS]
     -h                        Display this usage message
     -H hostname               Hostname to connect to
解釋器打印出來(lái)的字符串與它們輸入的形式完全相同:內(nèi)部的引號(hào),用反斜杠標(biāo)識(shí)的引號(hào)和各種怪字符,都精確的顯示出來(lái)。如果字符串中包含單引號(hào),不包含雙引號(hào),可以用雙引號(hào)引用它,反之可以用單引號(hào)。(后面介紹的print語(yǔ)句,可以可以用來(lái)寫沒(méi)有引號(hào)和反斜杠的字符串)。

字符串可以用+號(hào)聯(lián)接(或者說(shuō)粘合),也可以用*號(hào)循環(huán)。

>;>;>; word = 'Help' + 'A'
>;>;>; word
'HelpA'
>;>;>; '<' + word*5 + '>;'
'<HelpAHelpAHelpAHelpAHelpA>;'
兩個(gè)字符串值之間的聯(lián)接是自動(dòng)的,上例第一行可以寫成“word = 'Help' 'A'”這種方式只對(duì)字符串值有效,任何字符串表達(dá)式都不適用這種方法。

>;>;>; import string
>;>;>; 'str' 'ing'                   #  <-  This is ok
'string'
>;>;>; string.strip('str') + 'ing'   #  <-  This is ok
'string'
>;>;>; string.strip('str') 'ing'     #  <-  This is invalid
  File "<stdin>;", line 1, in ?
    string.strip('str') 'ing'
                            ^
SyntaxError: invalid syntax
字符串可以用下標(biāo)(索引)查詢;就像C一樣,字符串的第一個(gè)字符下標(biāo)是0。這里沒(méi)有獨(dú)立的字符類型,字符僅僅是大小為一的字符串。就像在Icon中那樣,字符串的子串可以通過(guò)切片標(biāo)志來(lái)表示:兩個(gè)由冒號(hào)隔開(kāi)的索引。

>;>;>; word[4]
'A'
>;>;>; word[0]
'He'
>;>;>; word[2]
'lp'
切片索引可以使用默認(rèn)值;省略前一個(gè)索引表示0,省略后一個(gè)索引表示被切片的字符串的長(zhǎng)度。

>;>;>; word[]    # The first two characters
'He'
>;>;>; word[2:]    # All but the first two characters
'lpA'
和C字符串不同,Python字符串不能改寫。按字符串索引賦值會(huì)產(chǎn)生錯(cuò)誤。

>;>;>; word[0] = 'x'
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
TypeError: object doesn't support item assignment
>;>;>; word[] = 'Splat'
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
TypeError: object doesn't support slice assignment
然而,可以通過(guò)簡(jiǎn)單有效的組合方式生成新的字符串:

>;>;>; 'x' + word[1:]
'xelpA'
>;>;>; 'Splat' + word[4]
'SplatA'
切片操作有一個(gè)很有用的不變性: s[] + s[i:] 等于s。

>;>;>; word[] + word[2:]
'HelpA'
>;>;>; word[] + word[3:]
'HelpA'
退化的切片索引被處理的很優(yōu)美:過(guò)大的索引代替為字符串大小,下界比上界大的返回空字符串。

>;>;>; word[1]
'elpA'
>;>;>; word[10:]
''
>;>;>; word[2]
''
索引可以是負(fù)數(shù),計(jì)數(shù)從右邊開(kāi)始,例如:

>;>;>; word[-1]     # The last character
'A'
>;>;>; word[-2]     # The last-but-one character
'p'
>;>;>; word[-2:]    # The last two characters
'pA'
>;>;>; word[:-2]    # All but the last two characters
'Hel'
不過(guò)-0還是0,所以它不是從右邊計(jì)數(shù)的!

>;>;>; word[-0]     # (since -0 equals 0)
'H'
越界的負(fù)切片索引會(huì)被截?cái),不過(guò)不要嘗試在前元素索引(非切片的)中這樣做:

>;>;>; word[-100:]
'HelpA'
>;>;>; word[-10]    # error
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
IndexError: string index out of range
理解切片的最好方式是把索引視為兩個(gè)字符之間的點(diǎn),第一個(gè)字符的左邊是0,字符串中第n個(gè)字符的右邊是索引n,例如:

+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0   1   2   3   4   5
-5  -4  -3  -2  -1
第一行是字符串中給定的0到5各個(gè)索引的位置,第二行是對(duì)應(yīng)的負(fù)索引。從i到j(luò)的切片由這兩個(gè)標(biāo)志之間的字符組成。

對(duì)于非負(fù)索引,切片長(zhǎng)度就是兩索引的差。例如,word[1]的長(zhǎng)度是2。

內(nèi)置函數(shù) len() 返回字符串長(zhǎng)度:

>;>;>; s = 'supercalifragilisticexpialidocious'
>;>;>; len(s)
34
  
3.1.3 Unicode 字符串
從Python2.0開(kāi)始,程序員們可以使用一種新的數(shù)據(jù)類型來(lái)存儲(chǔ)文本數(shù)據(jù):Unicode 對(duì)象。它可以用于存儲(chǔ)多種Unicode數(shù)據(jù)(請(qǐng)參閱 http://www.unicode.org/ ),并且,通過(guò)必要時(shí)的自動(dòng)轉(zhuǎn)換,它可以與現(xiàn)有的字符串對(duì)象良好的結(jié)合。

Unicode針對(duì)現(xiàn)代和舊式的文本中所有的字符提供了一個(gè)序列。以前,字符只能使用256個(gè)序號(hào),文本通常通過(guò)綁定代碼頁(yè)來(lái)與字符映射。這很容易導(dǎo)致混亂,特別是軟件的國(guó)際化(internationalization--通常寫做“i18n”--“i”+18 characters +“n”)。Unicode通過(guò)為所有字符定義一個(gè)統(tǒng)一的代碼頁(yè)解決了這個(gè)問(wèn)題。

Python中定義一個(gè)Unicode字符串和定義一個(gè)普通字符串一樣簡(jiǎn)單:

>;>;>; u'Hello World !'
u'Hello World !'
引號(hào)前小寫的“u”表示這里創(chuàng)建的是一個(gè)Unicode字符串。如果你想加入一個(gè)特殊字符,可以使用Python的 Unicode-Escape 編碼。如下例所示:

>;>;>; u'Hello\u0020World !'
u'Hello World !'
被替換的 \u0020 標(biāo)識(shí)表示在給定位置插入編碼值為 0x0020 的 Unicode字符(空格符)。

其它字符也會(huì)被直接解釋成對(duì)應(yīng)的Unicode碼。如果你有一個(gè)在西方國(guó)家常用的Latin-1編碼字符串,你可以發(fā)現(xiàn)Unicode字符集的前256個(gè)字符與Lation-1的對(duì)應(yīng)字符編碼完全相同。

另外,有一種與普通字符串相同的行模式。想要使用Python的Raw-Unicode-Escape 編碼,你需要在字符串的引號(hào)前加上 ur 前綴。如果在小寫“u”前可能有不止一個(gè)反斜杠,它只會(huì)把那些單獨(dú)的 \uXXXX 轉(zhuǎn)化為Unicode字符。

>;>;>; ur'Hello\u0020World !'
u'Hello World !'
>;>;>; ur'Hello\\u0020World !'
u'Hello\\\\u0020World !'
行模式在你需要輸入很多個(gè)反斜杠時(shí)很有用,可能會(huì)用于正規(guī)表達(dá)式。

作為這些編碼標(biāo)準(zhǔn)的一部分,Python提供了一個(gè)完備的方法集用于從已知的編碼集創(chuàng)建Unicode字符串。

內(nèi)置函數(shù)unicode() 提供了訪問(wèn)(編碼和解碼)所有已注冊(cè)的Unicode編碼的方法。它能轉(zhuǎn)換眾所周知的 Latin-1, ASCII, UTF-8, 和 UTF-16。后面的兩個(gè)可變長(zhǎng)編碼字符集用一個(gè)或多個(gè)byte存儲(chǔ)Unicode字符。默認(rèn)的字符集是 ASCII ,它只處理0到127的編碼,拒絕其它的字符并返回一個(gè)錯(cuò)誤。當(dāng)一個(gè)Unicode字符串被打印、寫入文件或通過(guò)str()轉(zhuǎn)化時(shí),它們被替換為默認(rèn)的編碼。

>;>;>; u"abc"
u'abc'
>;>;>; str(u"abc"
'abc'
>;>;>; u"&amp;&amp;ü"
u'\xe4\xf6\xfc'
>;>;>; str(u"&amp;&amp;ü"
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(12
要把一個(gè)Unicode字符串用指定的字符集轉(zhuǎn)化成8位字符串,可以使用Unicode對(duì)象提供的encode()方法,它有一個(gè)參數(shù)用以指定編碼名稱。編碼名稱小寫。

>;>;>; u"&amp;&amp;ü".encode('utf-8')
'\xc3\xa4\xc3\xb6\xc3\xbc'
如果你有一個(gè)特定編碼的字符串,想要把它轉(zhuǎn)為Unicode字符集,,可以使用uncode()函數(shù),它以編碼名做為第二個(gè)參數(shù)。

>;>;>; unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8')
u'\xe4\xf6\xfc'
  
3.1.4 鏈表
Python 已經(jīng)有了幾個(gè)復(fù)合數(shù)據(jù)類型,用于組織其它的值。最通用的是鏈表,它寫為中括之間用逗號(hào)分隔的一列值(子項(xiàng)),鏈表的子項(xiàng)不一定是同一類型的值。

>;>;>; a = ['spam', 'eggs', 100, 1234]
>;>;>; a
['spam', 'eggs', 100, 1234]
像字符串一樣,鏈表也以零開(kāi)始,可以被切片,聯(lián)接,等等:

>;>;>; a[0]
'spam'
>;>;>; a[3]
1234
>;>;>; a[-2]
100
>;>;>; a[1:-1]
['eggs', 100]
>;>;>; a[] + ['bacon', 2*2]
['spam', 'eggs', 'bacon', 4]
>;>;>; 3*a[] + ['Boe!']
['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boe!']
與不變的字符串不同,鏈表可以改變每個(gè)獨(dú)立元素的值:

>;>;>; a
['spam', 'eggs', 100, 1234]
>;>;>; a[2] = a[2] + 23
>;>;>; a
['spam', 'eggs', 123, 1234]
可以進(jìn)行切片操作,甚至還可以改變鏈表的大。

>;>;>; # Replace some items:
... a[0] = [1, 12]
>;>;>; a
[1, 12, 123, 1234]
>;>;>; # Remove some:
... a[0] = []
>;>;>; a
[123, 1234]
>;>;>; # Insert some:
... a[1] = ['bletch', 'xyzzy']
>;>;>; a
[123, 'bletch', 'xyzzy', 1234]
>;>;>; a[] = a     # Insert (a copy of) itself at the beginning
>;>;>; a
[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234]
內(nèi)置函數(shù)len()也同樣可以用于鏈表:

>;>;>; len(a)
8
它也可以嵌套鏈表(在鏈表中創(chuàng)建其它鏈表),例如:

>;>;>; q = [2, 3]
>;>;>; p = [1, q, 4]
>;>;>; len(p)
3
>;>;>; p[1]
[2, 3]
>;>;>; p[1][0]
2
>;>;>; p[1].append('xtra')     # See section 5.1
>;>;>; p
[1, [2, 3, 'xtra'], 4]
>;>;>; q
[2, 3, 'xtra']
注意最后一個(gè)例子,p[1]和q實(shí)際上指向同一個(gè)對(duì)象!我們?cè)诤竺鏁?huì)講到對(duì)象語(yǔ)法。

  
3.2 開(kāi)始編程
當(dāng)然,我們可以用Python做比2加2更復(fù)雜的事。例如,我們可以用以下的方法輸出菲波那契(Fibonacci)序列的子序列:

>;>;>; # Fibonacci series:
... # the sum of two elements defines the next
... a, b = 0, 1
>;>;>; while b < 10:
...       print b
...       a, b = b, a+b
...
1
1
2
3
5
8
示例中介紹了一些新功能:

第一行包括了復(fù)合參數(shù):變量a和b同時(shí)被賦值為0和1。最后一行又一次使用了這種技術(shù),證明了在賦值之前表達(dá)式右邊先進(jìn)行了運(yùn)算。右邊的表達(dá)式從左到右運(yùn)算。

while循環(huán)運(yùn)行在條件為真時(shí)執(zhí)行。在Python中,類似于C任何非零值為真,零為假。 這個(gè)條件也可以用于字符串或鏈表,事實(shí)上于對(duì)任何序列類型,長(zhǎng)度非零時(shí)為真,空序列為假。示例所用的是一個(gè)簡(jiǎn)單的比較。標(biāo)準(zhǔn)的比較運(yùn)算符寫法和C相同: < (小于),>; (大于),== (等于),<= (小于等于),>;=(大于等于)和!= (不等于)。

循環(huán)體是縮進(jìn)的:縮進(jìn)是Python對(duì)語(yǔ)句分組的方法。 Python仍沒(méi)有提供一個(gè)智能編輯功能所以你要在每一個(gè)縮進(jìn)行輸入一個(gè)tab或(一個(gè)或多個(gè))空格。 實(shí)際上你可能會(huì)準(zhǔn)備更為復(fù)雜的文本編輯器來(lái)編寫你的Python程序,大多數(shù)文本編輯器都提供了自動(dòng)縮進(jìn)功能。交互式的輸入一個(gè)復(fù)雜語(yǔ)句時(shí),需要用一個(gè)空行表示完成(因?yàn)榻忉屍鳑](méi)辦法猜出你什么時(shí)候輸入最后一行)。需要注意的是每一行都要有相同的空字符來(lái)標(biāo)識(shí)這是同一個(gè)語(yǔ)句塊。

print語(yǔ)句打印給定表達(dá)式的值。它與你僅僅輸入你需要的表達(dá)式(就像前面的計(jì)算器示例)不同,它可以同時(shí)輸出多個(gè)表達(dá)式。字符串輸出時(shí)沒(méi)有引號(hào),各項(xiàng)之間用一個(gè)空格分開(kāi),你可以很容易區(qū)分它們,如下所示:

>;>;>; i = 256*256
>;>;>; print 'The value of i is', i
The value of i is 65536
print語(yǔ)句末尾的逗號(hào)避免了輸出中的換行:

>;>;>; a, b = 0, 1
>;>;>; while b < 1000:
...     print b,
...     a, b = b, a+b
...
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
需要注意的是,如果最后一行仍沒(méi)有寫完,解釋器會(huì)在它打印下一個(gè)命令時(shí)插入一個(gè)新行。
作者: mq110    時(shí)間: 2005-05-31 16:49
標(biāo)題: Python 指南
4. 其它流程控制工具
除了前面介紹的 while 語(yǔ)句,Python 還從別的語(yǔ)言中借鑒了一些流程控制功能,并有所改變。

  
4.1 if 語(yǔ)句
也許最有句的語(yǔ)句類型是 if 語(yǔ)句。例如:

>;>;>; x = int(raw_input("lease enter an integer: ")
>;>;>; if x < 0:
...      x = 0
...      print 'Negative changed to zero'
... elif x == 0:
...      print 'Zero'
... elif x == 1:
...      print 'Single'
... else:
...      print 'More'
...
可能會(huì)有 0 或很多個(gè) elif 部分,else 是可選的。關(guān)鍵字“elif ” 是“ else if ”的縮寫,這個(gè)可以有效避免過(guò)深的縮進(jìn)。if ... elif ... elif ... 序列用于替代其它語(yǔ)言中的 switch 或 case 語(yǔ)句。
作者: mq110    時(shí)間: 2005-05-31 16:51
標(biāo)題: Python 指南
您的帖子中有論壇禁止發(fā)表的詞匯或內(nèi)容!
作者: mq110    時(shí)間: 2005-05-31 16:52
標(biāo)題: Python 指南
4.3 range() 函數(shù)
如果你需要一個(gè)數(shù)值序列,內(nèi)置函數(shù)range()可能會(huì)很有用,它生成一個(gè)等差級(jí)數(shù)鏈表。

>;>;>; range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(10)生成了一個(gè)包含10個(gè)值的鏈表,它準(zhǔn)確的用鏈表的索引值填充了這個(gè)長(zhǎng)度為10的列表,所生成的鏈表中不包括范圍中的結(jié)束值。也可以讓range操作從另一個(gè)數(shù)值開(kāi)始,或者可以指定一個(gè)不同的步進(jìn)值(甚至是負(fù)數(shù),有時(shí)這也被稱為“步長(zhǎng)”):

>;>;>; range(5, 10)
[5, 6, 7, 8, 9]
>;>;>; range(0, 10, 3)
[0, 3, 6, 9]
>;>;>; range(-10, -100, -30)
[-10, -40, -70]
需要迭代鏈表索引的話,如下所示結(jié)合使用range()和len():

>;>;>; a = ['Mary', 'had', 'a', 'little', 'lamb']
>;>;>; for i in range(len(a)):
...     print i, a
...
0 Mary
1 had
2 a
3 little
4 lamb
作者: mq110    時(shí)間: 2005-05-31 16:52
標(biāo)題: Python 指南
4.4 break 和 continue 語(yǔ)句, 以及循環(huán)中的 else 子句
break語(yǔ)句和C中的類似,用于跳出最近的一級(jí)for或while循環(huán)。

continue 語(yǔ)句是從C中借鑒來(lái)的,它表示循環(huán)繼續(xù)執(zhí)行下一次迭代。

循環(huán)可以有一個(gè)else子句;它在循環(huán)迭代完整個(gè)列表(對(duì)于for)或執(zhí)行條件為false(對(duì)于while)時(shí)執(zhí)行,但循環(huán)被break中止的情況下不會(huì)執(zhí)行。以下搜索素?cái)?shù)的示例程序演示了這個(gè)子句:

>;>;>; for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...            print n, 'equals', x, '*', n/x
...            break
...     else:
...          # loop fell through without finding a factor
...          print n, 'is a prime number'
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
  
4.5 pass 語(yǔ)句
pass 語(yǔ)句什么也不做。它用于那些語(yǔ)法上必須要有什么語(yǔ)句,但程序上什么也不要做的場(chǎng)合,例如:

>;>;>; while True:
...       pass # Busy-wait for keyboard interrupt
...
作者: mq110    時(shí)間: 2005-05-31 16:54
標(biāo)題: Python 指南
4.6 定義函數(shù)
我們可以編寫一個(gè)函數(shù)來(lái)生成有給定上界的菲波那契數(shù)列:

>;>;>; def fib(n):    # write Fibonacci series up to n
...     """rint a Fibonacci series up to n."""
...     a, b = 0, 1
...     while b < n:
...         print b,
...         a, b = b, a+b
...
>;>;>; # Now call the function we just defined:
... fib(2000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
關(guān)鍵字def 引入了一個(gè)函數(shù)定義。在其后必須跟有函數(shù)名和包括形式參數(shù)的圓括號(hào)。函數(shù)體語(yǔ)句從下一行開(kāi)始,必須是縮進(jìn)的。函數(shù)體的第一行可以是一個(gè)字符串值,這個(gè)字符串是該函數(shù)的 文檔字符串,也可稱作docstring。  

有些文檔字符串工具可以在線處理或打印文檔,或讓用戶交互的瀏覽代碼;在你的代碼中加入文檔字符串是一個(gè)好的作法,應(yīng)該養(yǎng)成習(xí)慣。

調(diào)用函數(shù)時(shí)會(huì)為局部變量引入一個(gè)新的符號(hào)表。所有的局部變量都存儲(chǔ)在這個(gè)局部符號(hào)表中。引用參數(shù)時(shí),會(huì)先從局部符號(hào)表中查找,然后是全局符號(hào)表,然后是內(nèi)置命名表。因此,全局參數(shù)雖然可以被引用,但它們不能在函數(shù)中直接賦值(除非它們用global語(yǔ)句命名)。

函數(shù)引用的實(shí)際參數(shù)在函數(shù)調(diào)用時(shí)引入局部符號(hào)表,因此,實(shí)參總是傳值調(diào)用(這里的值總是一個(gè)對(duì)象引用,而不是該對(duì)象的值)。4.1 一個(gè)函數(shù)被另一個(gè)函數(shù)調(diào)用時(shí),一個(gè)新的局部符號(hào)表在調(diào)用過(guò)程中被創(chuàng)建。

函數(shù)定義在當(dāng)前符號(hào)表中引入函數(shù)名。作為用戶定義函數(shù),函數(shù)名有一個(gè)為解釋器認(rèn)可的類型值。這個(gè)值可以賦給其它命名,使其能句做為一個(gè)函數(shù)來(lái)使用。這就像一個(gè)重命名機(jī)制:

>;>;>; fib
<function object at 10042ed0>;
>;>;>; f = fib
>;>;>; f(100)
1 1 2 3 5 8 13 21 34 55 89
你可能認(rèn)為fib不是一個(gè)函數(shù)(function),而是一個(gè)過(guò)程(procedure)。Python和C一樣,過(guò)程只是一個(gè)沒(méi)有返回值的函數(shù)。實(shí)際上,從技術(shù)上講,過(guò)程也有一個(gè)返回值,雖然是一個(gè)不討人喜歡的。這個(gè)值被稱為 None (這是一個(gè)內(nèi)置命名)。如果一個(gè)值只是None的話,通常解釋器不會(huì)寫一個(gè)None出來(lái),如果你真想要看它的話,可以這樣做:

>;>;>; print fib(0)
None
以下示列演示了如何從函數(shù)中返回一個(gè)包含菲波那契數(shù)列的數(shù)值鏈表,而不是打印它:

>;>;>; def fib2(n): # return Fibonacci series up to n
...     """Return a list containing the Fibonacci series up to n."""
...     result = []
...     a, b = 0, 1
...     while b < n:
...         result.append(b)    # see below
...         a, b = b, a+b
...     return result
...
>;>;>; f100 = fib2(100)    # call it
>;>;>; f100                # write the result
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
和以前一樣,這個(gè)例子演示了一些新的Python功能:
作者: mq110    時(shí)間: 2005-05-31 16:54
標(biāo)題: Python 指南
4.7 深入函數(shù)定義
有時(shí)需要定義參數(shù)個(gè)數(shù)可變的函數(shù)。有三個(gè)方法可以做到,我們可以組合使用它們。

  
4.7.1 參數(shù)默認(rèn)值
最有用的形式是給一個(gè)或多個(gè)參數(shù)指定默認(rèn)值。這樣創(chuàng)建的函數(shù)可以在調(diào)用時(shí)使用更少的參數(shù)。

def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
    while True:
        ok = raw_input(prompt)
        if ok in ('y', 'ye', 'yes'): return 1
        if ok in ('n', 'no', 'nop', 'nope'): return 0
        retries = retries - 1
        if retries < 0: raise IOError, 'refusenik user'
        print complaint
這個(gè)函數(shù)還可以用以下的方式調(diào)用:ask_ok('Do you really want to quit?'),或者像這樣:ask_ok('OK to overwrite the file?', 2)。

默認(rèn)值在函數(shù)定義段被解析,如下所示:

i = 5

def f(arg=i):
    print arg

i = 6
f()
will print 5.

重要警告:默認(rèn)值只會(huì)解析一次。當(dāng)默認(rèn)值是一個(gè)可變對(duì)象,諸如鏈表、字典或大部分類實(shí)例時(shí),會(huì)產(chǎn)生一些差異。例如,以下函數(shù)在后繼的調(diào)用中會(huì)積累它的參數(shù)值:

def f(a, L=[]):
    L.append(a)
    return L

print f(1)
print f(2)
print f(3)
這會(huì)打印出:

[1]
[1, 2]
[1, 2, 3]
如果你不想在不同的函數(shù)調(diào)用之間共享參數(shù)默認(rèn)值,可以如下面的實(shí)例一樣編寫函數(shù):

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L
  
4.7.2 參數(shù)關(guān)鍵字
函數(shù)可以通過(guò)參數(shù)關(guān)鍵字的形式來(lái)調(diào)用,形如“keyword = value”。例如,以下的函數(shù):

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print "-- This parrot wouldn't", action,
    print "if you put", voltage, "Volts through it."
    print "-- Lovely plumage, the", type
    print "-- It's", state, "!"
可以用以下的任一方法調(diào)用:

parrot(1000)
parrot(action = 'VOOOOOM', voltage = 1000000)
parrot('a thousand', state = 'pushing up the daisies')
parrot('a million', 'bereft of life', 'jump')
不過(guò)以下幾種調(diào)用是無(wú)效的:

parrot()                     # required argument missing(缺少必要參數(shù))
parrot(voltage=5.0, 'dead')  # non-keyword argument following keyword(在關(guān)鍵字后面有非關(guān)鍵字參數(shù))
parrot(110, voltage=220)     # duplicate value for argument(對(duì)參數(shù)進(jìn)行了重復(fù)賦值)
parrot(actor='John Cleese')  # unknown keyword(未知關(guān)鍵字)
通常,參數(shù)列表中的每一個(gè)關(guān)鍵字都必須來(lái)自于形式參數(shù),每個(gè)參數(shù)都有對(duì)應(yīng)的關(guān)鍵字。形式參數(shù)有沒(méi)有默認(rèn)值并不重要。實(shí)際參數(shù)不能一次賦多個(gè)值--形式參數(shù)不能在同一次調(diào)用中同時(shí)使用位置和關(guān)鍵字綁定值。這里有一個(gè)例子演示了在這種約束下所出現(xiàn)的失敗情況:

>;>;>; def function(a):
...     pass
...
>;>;>; function(0, a=0)
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
TypeError: function() got multiple values for keyword argument 'a'
引入一個(gè)形如 **name 的參數(shù)時(shí),它接收一個(gè)字典,該字典包含了所有未出現(xiàn)在形式參數(shù)列表中的關(guān)鍵字參數(shù)。這里可能還會(huì)組合使用一個(gè)形如 *name 的形式參數(shù),它接收一個(gè)拓?fù)洌ㄏ乱还?jié)中會(huì)詳細(xì)介紹),包含了所有沒(méi)有出現(xiàn)在形式參數(shù)列表中的參數(shù)值。(*name 必須在 **name 之前出現(xiàn)) 例如,我們這樣定義一個(gè)函數(shù):

def cheeseshop(kind, *arguments, **keywords):
    print "-- Do you have any", kind, '?'
    print "-- I'm sorry, we're all out of", kind
    for arg in arguments: print arg
    print '-'*40
    keys = keywords.keys()
    keys.sort()
    for kw in keys: print kw, ':', keywords[kw]
它可以像這樣調(diào)用:

cheeseshop('Limburger', "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           client='John Cleese',
           shopkeeper='Michael Palin',
           sketch='Cheese Shop Sketch')
當(dāng)然它會(huì)按如下內(nèi)容打。

-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
It's really very, VERY runny, sir.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch
注意sort()方法在關(guān)鍵字字典內(nèi)容打印前被調(diào)用,否則的話,打印參數(shù)時(shí)的順序是未定義的。

  
4.7.3 可變參數(shù)表
最后,一個(gè)最不常用的選擇是可以讓函數(shù)調(diào)用可變個(gè)數(shù)的參數(shù)。這些參數(shù)被包裝進(jìn)一個(gè)拓?fù)。在這些可變個(gè)數(shù)的參數(shù)之前,可以有零到多個(gè)普通的參數(shù):

def fprintf(file, format, *args):
    file.write(format % args)
  
4.7.4 Lambda 形式
出于適當(dāng)?shù)男枰,有幾種通常在功能性語(yǔ)言和Lisp中出現(xiàn)的功能加入到了Python。通過(guò)lambda關(guān)鍵字,可以創(chuàng)建很小的匿名函數(shù)。這里有一個(gè)函數(shù)返回它的兩個(gè)參數(shù)的和:“l(fā)ambda a, b: a+b”。 Lambda 形式可以用于任何需要的函數(shù)對(duì)象。出于語(yǔ)法限制,它們只能有一個(gè)單獨(dú)的表達(dá)式。語(yǔ)義上講,它們只是普通函數(shù)定義中的一個(gè)語(yǔ)法技巧。類似于嵌套函數(shù)定義,lambda形式可以從包含范圍內(nèi)引用變量:

>;>;>; def make_incrementor(n):
...     return lambda x: x + n
...
>;>;>; f = make_incrementor(42)
>;>;>; f(0)
42
>;>;>; f(1)
43
  
4.7.5 文檔字符串
這里介紹文檔字符串的概念和格式。

第一行應(yīng)該是關(guān)于對(duì)象用途的簡(jiǎn)介。簡(jiǎn)短起見(jiàn),不用明確的陳述對(duì)象名或類型,因?yàn)樗鼈兛梢詮膭e的途徑了解到(除非這個(gè)名字碰巧就是描述這個(gè)函數(shù)操作的動(dòng)詞)。這一行應(yīng)該以大寫字母開(kāi)頭,以句號(hào)結(jié)尾。

如果文檔字符串有多行,第二行應(yīng)該空出來(lái),與接下來(lái)的詳細(xì)描述明確分隔。接下來(lái)的文檔應(yīng)該有一或多段描述對(duì)象的調(diào)用約定、邊界效應(yīng)等。

Python的解釋器不會(huì)從多行的文檔字符串中去除縮進(jìn),所以必要的時(shí)候應(yīng)當(dāng)自己清除縮進(jìn)。這符合通常的習(xí)慣。第一行之后的第一個(gè)非空行決定了整個(gè)文檔的縮進(jìn)格式。(我們不用第一行是因?yàn)樗ǔ>o靠著起始的引號(hào),縮進(jìn)格式顯示的不清楚。)留白“相當(dāng)于”是字符串的起始縮進(jìn)。每一行都不應(yīng)該有縮進(jìn),如果有縮進(jìn)的話,所有的留白都應(yīng)該清除掉。相當(dāng)于留白就是驗(yàn)證后的制表符擴(kuò)展(通常是8個(gè)空格)。(這一段譯得不通,有疑問(wèn)的讀者請(qǐng)參見(jiàn)原文--譯者)

以下是一個(gè)多行文檔字符串的示例:

>;>;>; def my_function():
...     """Do nothing, but document it.
...
...     No, really, it doesn't do anything.
...     """
...     pass
...
>;>;>; print my_function.__doc__
Do nothing, but document it.

    No, really, it doesn't do anything.
作者: mq110    時(shí)間: 2005-05-31 16:55
標(biāo)題: Python 指南
5. 數(shù)據(jù)結(jié)構(gòu)
本章節(jié)深入講述一些你已經(jīng)學(xué)習(xí)過(guò)的東西,并且還加入了新的內(nèi)容。

  
5.1 深入鏈表
鏈表類型有很多方法,這里是鏈表類型的所有方法:

append(
x)


把一個(gè)元素添加到鏈表的結(jié)尾,相當(dāng)于 a[len(a):] = [x]。
extend(
L)


通過(guò)添加指定鏈表的所有元素來(lái)擴(kuò)充鏈表,相當(dāng)于 a[len(a):] = L 。
insert(
i, x)


在指定位置插入一個(gè)元素。第一個(gè)參數(shù)是準(zhǔn)備插入到其前面的那個(gè)元素的索引,例如 a.insert(0, x) 會(huì)插入到整個(gè)鏈表之前,而 a.insert(len(a), x) 相當(dāng)于 a.append(x)。
remove(
x)


刪除鏈表中值為x的第一個(gè)元素。如果沒(méi)有這樣的元素,就會(huì)返回一個(gè)錯(cuò)誤。
pop(
)


從鏈表的指定位置刪除元素,并將其返回。如果沒(méi)有指定索引,a.pop() 返回最后一個(gè)元素。元素隨即從鏈表中被刪除。(方法中i兩邊的方括號(hào)表示這個(gè)參數(shù)是可選的,而不是要求你輸入一對(duì)方括號(hào),你會(huì)經(jīng)常在Python 庫(kù)參考手冊(cè)中遇到這樣的標(biāo)記。)
index(
x)


返回鏈表中第一個(gè)值為x的元素的索引。如果沒(méi)有匹配的元素就會(huì)返回一個(gè)錯(cuò)誤。
count(
x)


返回x在鏈表中出現(xiàn)的次數(shù)。
sort(
)


對(duì)鏈表中的元素進(jìn)行適當(dāng)?shù)呐判颉?br /> reverse(
)


倒排鏈表中的元素。
下面這個(gè)示例演示了鏈表的大部分方法:

>;>;>; a = [66.6, 333, 333, 1, 1234.5]
>;>;>; print a.count(333), a.count(66.6), a.count('x')
2 1 0
>;>;>; a.insert(2, -1)
>;>;>; a.append(333)
>;>;>; a
[66.6, 333, -1, 333, 1, 1234.5, 333]
>;>;>; a.index(333)
1
>;>;>; a.remove(333)
>;>;>; a
[66.6, -1, 333, 1, 1234.5, 333]
>;>;>; a.reverse()
>;>;>; a
[333, 1234.5, 1, 333, -1, 66.6]
>;>;>; a.sort()
>;>;>; a
[-1, 1, 66.6, 333, 333, 1234.5]
  
5.1.1 把鏈表當(dāng)作堆棧使用
鏈表方法使得鏈表可以很方便的做為一個(gè)堆棧來(lái)使用,堆棧是這樣的數(shù)據(jù)結(jié)構(gòu),最先進(jìn)入的元素最后一個(gè)被釋放(后進(jìn)先出)。用 append() 方法可以把一個(gè)元素添加到堆棧頂。用不指定索引的 pop() 方法可以把一個(gè)元素從堆棧頂釋放出來(lái)。例如:

>;>;>; stack = [3, 4, 5]
>;>;>; stack.append(6)
>;>;>; stack.append(7)
>;>;>; stack
[3, 4, 5, 6, 7]
>;>;>; stack.pop()
7
>;>;>; stack
[3, 4, 5, 6]
>;>;>; stack.pop()
6
>;>;>; stack.pop()
5
>;>;>; stack
[3, 4]
  
5.1.2 把鏈表當(dāng)作隊(duì)列使用
你也可以把鏈表當(dāng)做隊(duì)列使用,隊(duì)列是這樣的數(shù)據(jù)結(jié)構(gòu),最先進(jìn)入的元素最先釋放(先進(jìn)先出)。使用 append()方法可以把元素添加到隊(duì)列最后,以0為參數(shù)調(diào)用 pop() 方法可以把最先進(jìn)入的元素釋放出來(lái)。例如:

>;>;>; queue = ["Eric", "John", "Michael"]
>;>;>; queue.append("Terry"           # Terry arrives
>;>;>; queue.append("Graham"          # Graham arrives
>;>;>; queue.pop(0)
'Eric'
>;>;>; queue.pop(0)
'John'
>;>;>; queue
['Michael', 'Terry', 'Graham']
  
5.1.3 函數(shù)化編程工具
對(duì)于鏈表來(lái)講,有三個(gè)內(nèi)置函數(shù)非常有用:filter(), map(), 和 reduce()。

“filter(function, sequence)” 返回一個(gè)序列(sequence),包括了給定序列中所有調(diào)用function(item)后返回值為true的元素。(如果可能的話,會(huì)返回相同的類型)。例如,以下程序可以計(jì)算部分素?cái)?shù):

>;>;>; def f(x): return x % 2 != 0 and x % 3 != 0
...
>;>;>; filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]
“map(function, sequence)” 為每一個(gè)元素依次調(diào)用 function(item) 并將返回值組成一個(gè)鏈表返回。例如,以下程序計(jì)算立方:

>;>;>; def cube(x): return x*x*x
...
>;>;>; map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
可以傳入多個(gè)序列,函數(shù)也必須要有對(duì)應(yīng)數(shù)量的參數(shù),執(zhí)行時(shí)會(huì)依次用各序列上對(duì)應(yīng)的元素來(lái)調(diào)用函數(shù)(如果某些序列比其它的短,就用None來(lái)代替)。如果把None做為一個(gè)函數(shù)傳入,則直接返回參數(shù)做為替代。

組合這兩種情況,我們會(huì)發(fā)現(xiàn)“map(None, list1, list2)”是把一對(duì)序列變成元素對(duì)序列的便捷方式。例如:

>;>;>; seq = range(
>;>;>; def square(x): return x*x
...
>;>;>; map(None, seq, map(square, seq))
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25), (6, 36), (7, 49)]
"reduce(func, sequence)" 返回一個(gè)單值,它是這樣構(gòu)造的:首先以序列的前兩個(gè)元素調(diào)用函數(shù),再以返回值和第三個(gè)參數(shù)調(diào)用,依次執(zhí)行下去。例如,以下程序計(jì)算1到10的整數(shù)之和:

>;>;>; def add(x,y): return x+y
...
>;>;>; reduce(add, range(1, 11))
55
如果序列中只有一個(gè)元素,就返回它,如果序列是空的,就拋出一個(gè)異常。

可以傳入第三個(gè)參數(shù)做為初始值。如果序列是空的,就返回初始值,否則函數(shù)會(huì)先接收初始值和序列的第一個(gè)元素,然后是返回值和下一個(gè)元素,依此類推。例如:

>;>;>; def sum(seq):
...     def add(x,y): return x+y
...     return reduce(add, seq, 0)
...
>;>;>; sum(range(1, 11))
55
>;>;>; sum([])
0
不要像示例中這樣定義 sum():因?yàn)楹嫌?jì)數(shù)值是一個(gè)通用的需求,在新的2.3版中,提供了內(nèi)置的 sum(sequence) 函數(shù)。

5.1.4 鏈表推導(dǎo)式
鏈表推導(dǎo)式提供了一個(gè)創(chuàng)建鏈表的簡(jiǎn)單途徑,無(wú)需使用 map(), filter() 以及 lambda。返回鏈表的定義通常要比創(chuàng)建這些鏈表更清晰。每一個(gè)鏈表推導(dǎo)式包括在一個(gè)for語(yǔ)句之后的表達(dá)式,零或多個(gè)for或if語(yǔ)句。返回值是由for或if子句之后的表達(dá)式得到的元素組成的鏈表。如果想要得到一個(gè)元組,必須要加上括號(hào)。

>;>;>; freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
>;>;>; [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>;>;>; vec = [2, 4, 6]
>;>;>; [3*x for x in vec]
[6, 12, 18]
>;>;>; [3*x for x in vec if x >; 3]
[12, 18]
>;>;>; [3*x for x in vec if x < 2]
[]
>;>;>; [[x,x**2] for x in vec]
[[2, 4], [4, 16], [6, 36]]
>;>;>; [x, x**2 for x in vec]      # error - parens required for tuples
  File "<stdin>;", line 1, in ?
    [x, x**2 for x in vec]
               ^
SyntaxError: invalid syntax
>;>;>; [(x, x**2) for x in vec]
[(2, 4), (4, 16), (6, 36)]
>;>;>; vec1 = [2, 4, 6]
>;>;>; vec2 = [4, 3, -9]
>;>;>; [x*y for x in vec1 for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>;>;>; [x+y for x in vec1 for y in vec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
>;>;>; [vec1*vec2 for i in range(len(vec1))]
[8, 12, -54]
為使鏈表推導(dǎo)式匹配for循環(huán)的行為,可以在推導(dǎo)之外保留循環(huán)變量:

>;>;>; x = 100                     # this gets overwritten
>;>;>; [x**3 for x in range(5)]
[0, 1, 8, 27, 64]
>;>;>; x                           # the final value for range(5)
4
  
5.2 del 語(yǔ)句
有一個(gè)方法可從鏈表中刪除指定索引的元素:del語(yǔ)句。這個(gè)方法也可以從鏈表中刪除切片(之前我們是把一個(gè)空鏈表賦給切片)。例如:

>;>;>; a = [-1, 1, 66.6, 333, 333, 1234.5]
>;>;>; del a[0]
>;>;>; a
[1, 66.6, 333, 333, 1234.5]
>;>;>; del a[2]
>;>;>; a
[1, 66.6, 1234.5]
del 也可以用于刪除整個(gè)變量:

>;>;>; del a
此后再引用這個(gè)名字會(huì)發(fā)生錯(cuò)誤(至少要到給它賦另一個(gè)值為止)。后面我們還會(huì)發(fā)現(xiàn)del的其它用法。

  
5.3 元組(Tuples)和序列(Sequences )
我們知道鏈表和字符串有很多通用的屬性,例如索引和切片操作。它們是序列類型中的兩種。因?yàn)镻ython是一個(gè)在不停進(jìn)化的語(yǔ)言,也可以加入其它的序列類型,這里有另一種標(biāo)準(zhǔn)序列類型:元組。

一個(gè)元組由數(shù)個(gè)逗號(hào)分隔的值組成,例如:

>;>;>; t = 12345, 54321, 'hello!'
>;>;>; t[0]
12345
>;>;>; t
(12345, 54321, 'hello!')
>;>;>; # Tuples may be nested:
... u = t, (1, 2, 3, 4, 5)
>;>;>; u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
如你所見(jiàn),元組在輸出時(shí)總是有括號(hào)的,以便于正確表達(dá)嵌套結(jié)構(gòu)。在輸入時(shí)可能有或沒(méi)有括號(hào)都可以,不過(guò)經(jīng)常括號(hào)都是必須的(如果元組是一個(gè)更大的表達(dá)式的一部分)。

元組有很多用途。例如(x, y)坐標(biāo)點(diǎn),數(shù)據(jù)庫(kù)中的員工記錄等等。元組就像字符串,不可改變:不能給元組的一個(gè)獨(dú)立的元素賦值(盡管你可以通過(guò)聯(lián)接和切片來(lái)模仿)。也可以通過(guò)包含可變對(duì)象來(lái)創(chuàng)建元組,例如鏈表。

一個(gè)特殊的問(wèn)題是構(gòu)造包含零個(gè)或一個(gè)元素的元組:為了適應(yīng)這種情況,語(yǔ)法上有一些額外的改變。一對(duì)空的括號(hào)可以創(chuàng)建空元組;要?jiǎng)?chuàng)建一個(gè)單元素元組可以在值后面跟一個(gè)逗號(hào)(在括號(hào)中放入一個(gè)單值是不夠的)。丑陋,但是有效。例如:

>;>;>; empty = ()
>;>;>; singleton = 'hello',    # <-- note trailing comma
>;>;>; len(empty)
0
>;>;>; len(singleton)
1
>;>;>; singleton
('hello',)
語(yǔ)句 t = 12345, 54321, 'hello!' 是元組封裝(sequence packing)的一個(gè)例子:值 12345, 54321 和 'hello!' 被封裝進(jìn)元組。其逆操作可能是這樣:

>;>;>; x, y, z = t
這個(gè)調(diào)用被稱為序列拆封非常合適。序列拆封要求左側(cè)的變量數(shù)目與序列的元素個(gè)數(shù)相同。要注意的是可變參數(shù)(multiple assignment

)其實(shí)只是元組封裝和序列拆封的一個(gè)結(jié)合!

這里有一點(diǎn)不對(duì)稱:封裝多重參數(shù)通常會(huì)創(chuàng)建一個(gè)元組,而拆封操作可以作用于任何序列。

  
5.4 字典(Dictionaries)
另一個(gè)非常有用的Python內(nèi)建數(shù)據(jù)類型是字典(Dictionaries)。字典在某些語(yǔ)言中可能稱為“聯(lián)合內(nèi)存”(``associative memories'')或“聯(lián)合數(shù)組”(``associative arrays'')。序列是以連續(xù)的整數(shù)為索引,與此不同的是,字典以關(guān)鍵字為索引,關(guān)鍵字可以是任意不可變類型,通常用字符串或數(shù)值。如果元組中只包含字符串和數(shù)字,它可以做為關(guān)鍵字,如果它直接或間接的包含了可變對(duì)象,就不能當(dāng)做關(guān)鍵字。不能用鏈表做關(guān)鍵字,因?yàn)殒湵砜梢杂盟鼈兊?append() 和 extend() 方法,或者用切片、或者通過(guò)檢索變量來(lái)即時(shí)改變。

理解字典的最佳方式是把它看做無(wú)序的關(guān)鍵字:值對(duì)( key:value pairs )集合,關(guān)鍵字必須是互不相同的(在同一個(gè)字典之內(nèi))。一對(duì)大括號(hào)創(chuàng)建一個(gè)空的字典:{}。初始化鏈表時(shí),在大括號(hào)內(nèi)放置一組逗號(hào)分隔的關(guān)鍵字:值對(duì),這也是字典輸出的方式。

字典的主要操作是依據(jù)關(guān)鍵字來(lái)存儲(chǔ)和析取值。也可以用del來(lái)刪除關(guān)鍵字:值對(duì)。如果你用一個(gè)已經(jīng)存在的關(guān)鍵字存儲(chǔ)值,以前為該關(guān)鍵字分配的值就會(huì)被遺忘。試圖析取從一個(gè)不存在的關(guān)鍵字中讀取值會(huì)導(dǎo)致錯(cuò)誤。

字典的keys() 方法返回由所有關(guān)鍵字組成的鏈表,該鏈表的順序不定(如果你需要它有序,只能調(diào)用關(guān)鍵字鏈表的sort()方法)。使用字典的 has_key() 方法可以檢查字典中是否存在某一關(guān)鍵字。

這是一個(gè)關(guān)于字典應(yīng)用的小示例:

>;>;>; tel = {'jack': 4098, 'sape': 4139}
>;>;>; tel['guido'] = 4127
>;>;>; tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>;>;>; tel['jack']
4098
>;>;>; del tel['sape']
>;>;>; tel['irv'] = 4127
>;>;>; tel
{'guido': 4127, 'irv': 4127, 'jack': 4098}
>;>;>; tel.keys()
['guido', 'irv', 'jack']
>;>;>; tel.has_key('guido')
True
鏈表中存儲(chǔ)關(guān)鍵字-值對(duì)元組的話,字典可以從中直接構(gòu)造。關(guān)鍵字-值對(duì)來(lái)自一個(gè)模式時(shí),可以用鏈表推導(dǎo)式簡(jiǎn)單的表達(dá)關(guān)鍵字-值鏈表。

>;>;>; dict([('sape', 4139), ('guido', 4127), ('jack', 409])
{'sape': 4139, 'jack': 4098, 'guido': 4127}
>;>;>; dict([(x, x**2) for x in vec])     # use a list comprehension
{2: 4, 4: 16, 6: 36}
  
5.5 循環(huán)技巧
在字典中循環(huán)時(shí),關(guān)鍵字和對(duì)應(yīng)的值可以使用 items() 方法同時(shí)解讀出來(lái)。

>;>;>; knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>;>;>; for k, v in knights.items():
...     print k, v
...
gallahad the pure
robin the brave
在序列中循環(huán)時(shí),索引位置和對(duì)應(yīng)值可以使用 enumerate() 函數(shù)同時(shí)得到。


>;>;>; for i, v in enumerate(['tic', 'tac', 'toe']):
...     print i, v
...
0 tic
1 tac
2 toe
同時(shí)循環(huán)兩個(gè)或更多的序列,可以使用 zip() 整體解讀。

>;>;>; questions = ['name', 'quest', 'favorite color']
>;>;>; answers = ['lancelot', 'the holy grail', 'blue']
>;>;>; for q, a in zip(questions, answers):
...     print 'What is your %s?  It is %s.' % (q, a)
...     
What is your name?  It is lancelot.
What is your quest?  It is the holy grail.
What is your favorite color?  It is blue.
  
5.6 深入條件控制
用于while和if語(yǔ)句的條件包括了比較之外的操作符。

in和not比較操作符審核值是否在一個(gè)區(qū)間之內(nèi)。操作符is和is not比較兩個(gè)對(duì)象是否相同;這只和諸如鏈表這樣的可變對(duì)象有關(guān)。所有的比較操作符具有相同的優(yōu)先級(jí),低于所有的數(shù)值操作。

比較操作可以傳遞。例如 a < b == c 審核是否a小于b并b等于c。

比較操作可以通過(guò)邏輯操作符and和or組合,比較的結(jié)果可以用not來(lái)取反義。這些操作符的優(yōu)先級(jí)又低于比較操作符,在它們之中,not具有最高的優(yōu)先級(jí),or的優(yōu)先組最低,所以A and not B or C 等于 (A and (not B)) or C。當(dāng)然,表達(dá)式可以用期望的方式表示。

邏輯操作符and 和or 也稱作短路操作符:它們的參數(shù)從左向右解析,一旦結(jié)果可以確定就停止。例如,如果A和C為真而B(niǎo)為假,A and B and C 不會(huì)解析C。作用于一個(gè)普通的非邏輯值時(shí),短路操作符的返回值通常是最后一個(gè)變量。

可以把比較或其它邏輯表達(dá)式的返回值賦給一個(gè)變量,例如:

>;>;>; string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
>;>;>; non_null = string1 or string2 or string3
>;>;>; non_null
'Trondheim'
需要注意的是Python與C不同,內(nèi)部表達(dá)式不能分配值。C 程序員經(jīng)常對(duì)此抱怨,不過(guò)它避免了一類在C程序中司空見(jiàn)慣的錯(cuò)誤:想要在解析式中使==時(shí)誤用了=操作符。

  
5.7 比較序列和其它類型
序列對(duì)象可以與相同類型的其它對(duì)象比較。比較操作按字典序進(jìn)行:首先比較前兩個(gè)元素,如果不同,就決定了比較的結(jié)果;如果相同,就比較后兩個(gè)元素,依此類推,直到所有序列都完成比較。如果兩個(gè)元素本身就是同樣類型的序列,就遞歸字典序比較。如果兩個(gè)序列的所有子項(xiàng)都相等,就認(rèn)為序列相等。如果一個(gè)序列是另一個(gè)序列的初始子序列,較短的一個(gè)序列就小于另一個(gè)。字符串的字典序按照單字符的ASCII順序。下面是同類型序列之間比較的一些例子:

(1, 2, 3)              < (1, 2, 4)
[1, 2, 3]              < [1, 2, 4]
'ABC' < 'C' < 'Pascal' < 'Python'
(1, 2, 3, 4)           < (1, 2, 4)
(1, 2)                 < (1, 2, -1)
(1, 2, 3)             == (1.0, 2.0, 3.0)
(1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)
需要注意的是不同類型的對(duì)象比較是合法的。輸出結(jié)果是確定而非任意的:類型按它們的名字排序。因而,一個(gè)鏈表(list)總是小于一個(gè)字符串(string),一個(gè)字符串(string)總是小于一個(gè)元組(tuple)等等。數(shù)值類型比較時(shí)會(huì)統(tǒng)一它們的數(shù)據(jù)類型,所以0等于0.0,等等。5.1
作者: mq110    時(shí)間: 2005-05-31 16:55
標(biāo)題: Python 指南
6. 模塊
如果你退出Python解釋器重新進(jìn)入,以前創(chuàng)建的一切定義(變量和函數(shù))就全部丟失了。因此,如果你想寫一些長(zhǎng)久保存的程序,最好使用一個(gè)文本編輯器來(lái)編寫程序,把保存好的文件輸入解釋器。我們稱之為創(chuàng)建一個(gè)腳本。程序變得更長(zhǎng)一些了,你可能為了方便維護(hù)而把它分離成幾個(gè)文件。你也可能想要在幾個(gè)程序中都使用一個(gè)常用的函數(shù),但是不想把它的定義復(fù)制到每一個(gè)程序里。

為了支持這些需要,Python提供了一個(gè)方法可以從文件中獲取定義,在腳本或者解釋器的一個(gè)交互式實(shí)例中使用。這樣的文件被稱為實(shí)例;模塊中的定義可以導(dǎo)入到另一個(gè)模塊或主模塊中(在腳本執(zhí)行時(shí)可以調(diào)用的變量集位于最高級(jí),并且處于計(jì)算器模式)

模塊是包括Python定義和聲明的文件。文件名就是模塊名加上.py后綴。模塊的模塊名(做為一個(gè)字符串)可以由全局變量__name__得到。例如,你可以用自己慣用的文件編輯器在當(dāng)前目錄下創(chuàng)建一個(gè)叫fibo.py的文件,錄入如下內(nèi)容:

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print b,
        a, b = b, a+b

def fib2(n): # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result
現(xiàn)在進(jìn)入Python解釋器用如下命令導(dǎo)入這個(gè)模塊:

>;>;>; import fibo
這樣做不會(huì)直接把fibo中的函數(shù)導(dǎo)入當(dāng)前的語(yǔ)義表;,它只是引入了模塊名fibo。你可以通過(guò)模塊名按如下方式訪問(wèn)這個(gè)函數(shù):

>;>;>; fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>;>;>; fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>;>;>; fibo.__name__
'fibo'
如果你想要直接調(diào)用函數(shù),通?梢越o它賦一個(gè)本地名稱:

>;>;>; fib = fibo.fib
>;>;>; fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
  
6.1 深入模塊
模塊可以像函數(shù)定義一樣包含執(zhí)行語(yǔ)句。這些語(yǔ)句通常用于初始化模塊。它們只在模塊第一次導(dǎo)入時(shí)執(zhí)行一次。6.1

對(duì)應(yīng)于定義模塊中所有函數(shù)的全局語(yǔ)義表,每一個(gè)模塊有自己的私有語(yǔ)義表。因此,模塊作者可以在模塊中使用一些全局變量,不會(huì)因?yàn)榕c用戶的全局變量沖突而引發(fā)錯(cuò)誤。另一方面,如果你確定你需要這個(gè),可以像引用模塊中的函數(shù)一樣獲取模塊中的全局變量,形如:modname.itemname。

模塊可以導(dǎo)入(import)其它模塊。習(xí)慣上所有的import語(yǔ)句都放在模塊(或腳本,等等)的開(kāi)頭,但這并不是必須的。被導(dǎo)入的模塊名入在本模塊的全局語(yǔ)義表中。

import語(yǔ)句的一個(gè)變體直接從被導(dǎo)入的模塊中導(dǎo)入命名到本模塊的語(yǔ)義表中。例如:

>;>;>; from fibo import fib, fib2
>;>;>; fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
這樣不會(huì)從局域語(yǔ)義表中導(dǎo)入模塊名(例如,fibo沒(méi)有定義)。

這里還有一個(gè)變體從模塊定義中導(dǎo)入所有命名:

>;>;>; from fibo import *
>;>;>; fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
這樣可以導(dǎo)入所有除了以下劃線(_)開(kāi)頭的命名。

  
6.1.1 模塊搜索路徑
導(dǎo)入一個(gè)叫spam的模塊時(shí),解釋器先在當(dāng)前目錄中搜索名為spam.py的文件,然后在環(huán)境變量PYTHONPATH指琮的目錄列表中搜索,然后是環(huán)境變量PATH中的路徑列表。如果PYTHONPATH沒(méi)有設(shè)置,或者文件沒(méi)有找到,接下來(lái)搜索安裝目錄,在UNIX中,通常是 .:/usr/local/lib/python。

實(shí)際上,解釋器由sys.path變量指定的路徑目錄搜索模塊,該變量初始化時(shí)默認(rèn)包含了輸入腳本(或者當(dāng)前目錄),PATHPATH和安裝目錄。這樣就允許Python程序(原文如此,programs;我猜想應(yīng)該是“programer”,程序員--譯者)了解如何修改或替換模塊搜索目錄。需要注意的是由于這些目錄中包含有搜索路徑中運(yùn)行的腳本,所以這些腳本不應(yīng)該和標(biāo)準(zhǔn)模塊重名,否則在導(dǎo)入模塊時(shí)Python會(huì)嘗試把這些腳本當(dāng)作模塊來(lái)加載。這通常會(huì)引發(fā)一個(gè)錯(cuò)誤。請(qǐng)參見(jiàn) 6.2節(jié)“標(biāo)準(zhǔn)模塊”以了解更多的信息。

6.1.2 “編譯”Python文件
對(duì)于引用了大量標(biāo)準(zhǔn)模塊的短程序,有一個(gè)提高啟動(dòng)速度有重要方法,如果在spam.py目錄下存在一個(gè)名為spam.pyc的文件,它會(huì)被視為spam模塊的預(yù)“編譯”(``byte-compiled'' ,二進(jìn)制編譯)版本。用于創(chuàng)建spam.pyc的這一版spam.py的修改時(shí)間記錄在spam.pyc文件中,如果兩者不匹配,.pyc文件就被忽略。

通常你不需要為創(chuàng)建spam.pyc文件做任何工作。一旦spam.py成功編譯,就會(huì)試圖編譯對(duì)應(yīng)版本的spam.pyc。如果有任何原因?qū)е聦懭氩怀晒,返回的spam.pyc文件就會(huì)視為無(wú)效,隨后即被忽略。spam.pyc文件的內(nèi)容是平臺(tái)獨(dú)立的,所以Python模塊目錄可以在不同架構(gòu)的機(jī)器之間共享。

部分高級(jí)技巧:

以-O參數(shù)調(diào)用Python解釋器時(shí),會(huì)生成優(yōu)化代碼并保存在.pyo文件中。通用的優(yōu)化器沒(méi)有太多幫助;它只是刪除了斷言(assert)語(yǔ)句。使用-O參數(shù),所有的代碼都會(huì)被優(yōu)化;.pyc文件被忽略,.py文件被編譯為優(yōu)化代碼。

向Python解釋器傳遞兩個(gè) -O 參數(shù)(-OO)會(huì)執(zhí)行完全優(yōu)化的二進(jìn)制優(yōu)化編譯,這偶爾會(huì)生成錯(cuò)誤的程序。當(dāng)前,壓縮的.pyo文件只是從二進(jìn)制代碼中刪除了__doc__字符串。因?yàn)槟承┏绦蛞蕾囉谶@些變量的可用性,你應(yīng)該只在確定無(wú)誤的場(chǎng)合使用這一選項(xiàng)。

來(lái)自.pyc文件或.pyo文件中的程序不會(huì)比來(lái)自.py文件的運(yùn)行更快;.pyc或.pyo文件只是在它們加載的時(shí)候更快一些。

通過(guò)腳本名在命令行運(yùn)行腳本時(shí),不會(huì)為該腳本向創(chuàng)建.pyc或.pyo文件的二進(jìn)制代碼。當(dāng)然,把腳本的主要代碼移進(jìn)一個(gè)模塊里,然后用一個(gè)小的解構(gòu)腳本導(dǎo)入這個(gè)模塊,就可以提高腳本的啟動(dòng)速度。也可以直接在命令行中指定一個(gè).pyc或乾.pyo文件。

對(duì)于同一個(gè)模塊(這里指例程spam--譯者),可以只有spam.pyc文件(或者spam.pyo,在使用 -O 參數(shù)時(shí))而沒(méi)有spam.py文件。這樣可以打包發(fā)布比較于逆向工程的Python代碼庫(kù)。

compileall模塊 可以為指定目錄中的所有模塊創(chuàng)建.pyc文件(或者使用-O參數(shù)創(chuàng)建.pyo文件)。

  
6.2 標(biāo)準(zhǔn)模塊
Python帶有一個(gè)標(biāo)準(zhǔn)模塊庫(kù),并發(fā)布有獨(dú)立的文檔,名為 Python 庫(kù)參考手冊(cè) (此后稱其為“庫(kù)參考手冊(cè)”)。有一些模塊內(nèi)置于解釋器之中,這些操作的訪問(wèn)接口不是語(yǔ)言內(nèi)核的一部分,但是已經(jīng)內(nèi)置于解釋器了。這既是為了提高效率,也是為了給系統(tǒng)調(diào)用等操作系統(tǒng)原生訪問(wèn)提供接口。這類模塊集合是一個(gè)依賴于底層平臺(tái)的配置選項(xiàng)。例如,amoeba模塊只提供對(duì)Amoeba原生系統(tǒng)的支持。有一個(gè)具體的模塊值得注意:sys ,這個(gè)模塊內(nèi)置于所有的Python解釋器。變量 sys.ps1 和 sys.ps2 定義了主提示符和副助提示符字符串:

>;>;>; import sys
>;>;>; sys.ps1
'>;>;>; '
>;>;>; sys.ps2
'... '
>;>;>; sys.ps1 = 'C>; '
C>; print 'Yuck!'
Yuck!
C>;
這兩個(gè)變量只在解釋器的交互模式下有意義(此處原文為:These two variables are only defined if the interpreter is in interactive mode. )。

變量sys.path 是解釋器模塊搜索路徑的字符串列表。它由環(huán)境變量PYTHONPATH初始化,如果PYTHONPATH沒(méi)有內(nèi)定,就由內(nèi)置的默認(rèn)值初始化。你可以用標(biāo)準(zhǔn)和字符串操作修改它:

>;>;>; import sys
>;>;>; sys.path.append('/ufs/guido/lib/python')
  
6.3 dir() 函數(shù)
內(nèi)置函數(shù)dir()用于按模塊名搜索模塊定義,它返回一個(gè)字符串類型的存儲(chǔ)列表:

>;>;>; import fibo, sys
>;>;>; dir(fibo)
['__name__', 'fib', 'fib2']
>;>;>; dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__',
'__stdin__', '__stdout__', '_getframe', 'api_version', 'argv',
'builtin_module_names', 'byteorder', 'callstats', 'copyright',
'displayhook', 'exc_clear', 'exc_info', 'exc_type', 'excepthook',
'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags',
'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache',
'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout',
'version', 'version_info', 'warnoptions']
無(wú)參數(shù)調(diào)用時(shí),dir()函數(shù)返回你當(dāng)前定義的名稱:

>;>;>; a = [1, 2, 3, 4, 5]
>;>;>; import fibo, sys
>;>;>; fib = fibo.fib
>;>;>; dir()
['__name__', 'a', 'fib', 'fibo', 'sys']
應(yīng)該該列表列出了所有類型的名稱:變量,模塊,函數(shù),等等:

dir()不會(huì)列出內(nèi)置函數(shù)和變量名。如果你想列出這此內(nèi)容,它們?cè)跇?biāo)準(zhǔn)模塊__buildin__中定義:

>;>;>; import __builtin__
>;>;>; dir(__builtin__)
['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',
'PendingDeprecationWarning', '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',
'enumerate', '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', 'string', 'sum', 'super',
'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
  
6.4 包
包通常是使用用“圓點(diǎn)模塊名”的結(jié)構(gòu)化模塊命名空間。例如,名為A.B的模塊表示了名為“A”的包中名為“B”的子模塊。正如同用模塊來(lái)保存不同的模塊架構(gòu)可以避免全局變量之間的相互沖突,使用圓點(diǎn)模塊名保存像NunPy或Python Imaging Library之類的不同類庫(kù)架構(gòu)可以避免模塊之間的命名沖突。

假設(shè)你現(xiàn)在想要設(shè)計(jì)一個(gè)模塊集(一個(gè)“包”)來(lái)統(tǒng)一處理聲音文件和聲音數(shù)據(jù)。存在幾種不同的聲音格式(通常由它們的擴(kuò)展名來(lái)標(biāo)識(shí),例如:.wav,.aiff,.au),于是,為了在不同類型的文件格式之間轉(zhuǎn)換,你需要維護(hù)一個(gè)不斷增長(zhǎng)的包集合?赡苣氵想要對(duì)聲音數(shù)據(jù)做很多不同的操作(例如混音,添加回聲,應(yīng)用平衡功能,創(chuàng)建一個(gè)人造效果),所以你要加入一個(gè)無(wú)限流模塊來(lái)執(zhí)行這些操作。你的包可能會(huì)是這個(gè)樣子(通過(guò)分級(jí)的文件體系來(lái)進(jìn)行分組):

Sound/                          Top-level package
      __init__.py               Initialize the sound package
      Formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      Effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      Filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...
導(dǎo)入模塊時(shí),Python通過(guò)sys.path中的目錄列表來(lái)搜索存放包的子目錄。

必須要有一個(gè)__init__.py 文件的存在,才能使Python視該目錄為一個(gè)包;這是為了防止某些目錄使用了“string”這樣的通用名而無(wú)意中在隨后的模塊搜索路徑中覆蓋了正確的模塊。最簡(jiǎn)單的情況下,__init__.py 可以只是一個(gè)空文件,不過(guò)它也可能包含了包的初始化代碼,或者設(shè)置了 __all__ 變量,后面會(huì)有相關(guān)介紹。

包用戶可以從包中導(dǎo)入合法的模塊,例如:

import Sound.Effects.echo
這樣就導(dǎo)入了Sound.Effects.echo子模塊。它必需通過(guò)完整的名稱來(lái)引用。

Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4)
導(dǎo)入包時(shí)有一個(gè)可以選擇的方式:

from Sound.Effects import echo
這樣就加載了echo子模塊,并且使得它在沒(méi)有包前綴的情況下也可以使用,所以它可以如下方式調(diào)用:

echo.echofilter(input, output, delay=0.7, atten=4)
還有另一種變體用于直接導(dǎo)入函數(shù)或變量:

from Sound.Effects.echo import echofilter
這樣就又一次加載了echo子模塊,但這樣就可以直接調(diào)用它的 echofilter() 函數(shù):

echofilter(input, output, delay=0.7, atten=4)
需要注意的是使用 from package import item 方式導(dǎo)入包時(shí),這個(gè)子項(xiàng)(item)既可以是包中的一個(gè)子模塊(或一個(gè)子包),也可以是包中定義的其它命名,像函數(shù)、類或變量。import 語(yǔ)句首先核對(duì)是否包中有這個(gè)子項(xiàng),如果沒(méi)有,它假定這是一個(gè)模塊,并嘗試加載它。如果沒(méi)有找到它,會(huì)引發(fā)一個(gè) ImportError 異常。

相反,使用類似import item.subitem.subsubitem 這樣的語(yǔ)法時(shí),這些子項(xiàng)必須是包,最后的子項(xiàng)可以是包或模塊,但不能是前面子項(xiàng)中定義的類、函數(shù)或變量。

  
6.4.1 從包中導(dǎo)入全部信息(Importing * From a Package)
那么當(dāng)用戶寫下from Sound.Effects import *時(shí)會(huì)發(fā)生什么事?理想中,總是希望在文件系統(tǒng)中找出包中所有的子模塊,然后導(dǎo)入它們。不幸的是,這個(gè)操作在Mac 和 Windows 平臺(tái)上工作的并不太好,這些文件系統(tǒng)的文件大小寫并不敏感!在這些平臺(tái)上沒(méi)有什么方法可以確保一個(gè)叫ECHO.PY的文件應(yīng)該導(dǎo)入為模塊echo、Echo或ECHO。(例如,Windows 95有一個(gè)討厭的習(xí)慣,它會(huì)把所有的文件名都顯示為首字母大寫的風(fēng)格。) DOS 8+3文件名限制又給長(zhǎng)文件名模塊帶來(lái)了另一個(gè)有趣的問(wèn)題。

對(duì)于包的作者來(lái)說(shuō)唯一的解決方案就是給提供一個(gè)明確的包索引。import語(yǔ)句按如下條件進(jìn)行轉(zhuǎn)換:執(zhí)行from packae import * 時(shí),如果包中的__init__.py代碼定義了一個(gè)名為_(kāi)_all__的鏈表,就會(huì)按照鏈表中給出的模塊名進(jìn)行導(dǎo)入。新版本的包發(fā)布時(shí)作者可以任意更新這個(gè)鏈表。如果包作者不想import * 的時(shí)候?qū)胨麄兊陌兴心K,那么也可能會(huì)決定不支持它(import *)。例如,Sounds/Effects/__init__.py 這個(gè)文件可能包括如下代碼:

__all__ = ["echo", "surround", "reverse"]
這意味著 from Sound.Effects import * 語(yǔ)句會(huì)從Sound 包中導(dǎo)入以上三個(gè)已命名的子模塊。

如果沒(méi)有定義 __all__ ,from Sound.Effects import * 語(yǔ)句不會(huì)從Sound.Effects包中導(dǎo)入所有的子模塊。Effects 導(dǎo)入到當(dāng)前的命名空間,只能確定的是導(dǎo)入了 Sound.Effects 包(可能會(huì)運(yùn)行 __init__.py中的初始化代碼)以及包中定義的所有命名會(huì)隨之導(dǎo)入。這樣就從__init__.py中導(dǎo)入了每一個(gè)命名(以及明確導(dǎo)入的子模塊)。同樣也包括了前述的import語(yǔ)句從包中明確導(dǎo)入的子模塊,考慮以下代碼:

import Sound.Effects.echo
import Sound.Effects.surround
from Sound.Effects import *
在這個(gè)例子中,echo和surround模塊導(dǎo)入了當(dāng)前的命名空間,這是因?yàn)閳?zhí)行from ... import語(yǔ)句時(shí)它們已經(jīng)定義在Sound.Effects包中了(定義了__all__時(shí)也會(huì)同樣工作)。

需要注意的是習(xí)慣上不主張從一個(gè)包或模塊中用import * 導(dǎo)入所有模塊,因?yàn)檫@樣的通常意味著可讀性會(huì)很差。然而,在交互會(huì)話中這樣做可以減少輸入,相對(duì)來(lái)說(shuō)確定的模塊被設(shè)計(jì)成只導(dǎo)出確定的模式中命名的那一部分。

記住,from Package import specific_submodule沒(méi)有錯(cuò)誤!事實(shí)上,除非導(dǎo)入的模塊需要使用其它包中的同名子模塊,否則這是受到推薦的寫法。

6.4.2 內(nèi)置包(Intra-package)參考
子模塊之間經(jīng)常需要互相引用。例如,surround 模塊可能會(huì)引用echo 模塊。事實(shí)上,這樣的引用如此普遍,以致于import語(yǔ)句會(huì)先搜索包內(nèi)部,然后才是標(biāo)準(zhǔn)模塊搜索路徑。因此surround module 可以簡(jiǎn)單的調(diào)用import echo 或者 from echo import echofilter。如果沒(méi)有在當(dāng)前的包中發(fā)現(xiàn)要導(dǎo)入的模塊,import語(yǔ)句會(huì)依據(jù)指定名尋找一個(gè)頂級(jí)模塊。

如果包中使用了子包結(jié)構(gòu)(就像示例中的Sound包),不存在什么從鄰近的包中引用子模塊的便捷方法--必須使用子包的全名。例如,如果Sound.Filters.vocoder 包需要使用Sound.Effects 包中的echosa模塊,它可以使用from Sound.Effects import echo。

6.4.3 多重路徑中的包
包支持一個(gè)另為特殊的變量, __path__。 在包的__init__.py文件代碼執(zhí)行之前,該變量初始化一個(gè)目錄名列表。該變量可以修改,它作用于包中的子包和模塊的搜索功能。

這個(gè)功能可以用于擴(kuò)展包中的模塊集,不過(guò)它不常用。
作者: mq110    時(shí)間: 2005-05-31 16:56
標(biāo)題: Python 指南
7. 輸入和輸出
有幾種方法可以表現(xiàn)程序的輸出結(jié)果;數(shù)據(jù)可以用可讀的結(jié)構(gòu)打印,也可以寫入文件供以后使用。本章將會(huì)討論幾種可行的做法。

  
7.1 設(shè)計(jì)輸出格式
我們有兩種大相徑庭的輸出值方法:表達(dá)式語(yǔ)句和print語(yǔ)句。(第三種訪求是使用文件對(duì)象的wite()方法,標(biāo)準(zhǔn)文件輸出可以參考sys.stdout。詳細(xì)內(nèi)容參見(jiàn)庫(kù)參考手冊(cè)。)

可能你經(jīng)常想要對(duì)輸出格式做一些比簡(jiǎn)單的打印空格分隔符更為復(fù)雜的控制。有兩種方法可以格式化輸出。第一種是由你來(lái)控制整個(gè)字符串,使用字符切片和聯(lián)接操作就可以創(chuàng)建出任何你想要的輸出形式。標(biāo)準(zhǔn)模塊 string 包括了一些操作,將字符串填充入給定列時(shí),這些操作很有用。隨后我們會(huì)討論這部分內(nèi)容。第二種方法是使用 % 操作符,以某個(gè)字符串做為其左參數(shù)。 % 操作符將左參數(shù)解釋為類似于 sprintf()風(fēng)格的格式字符串,并作用于右參數(shù),從該操作中返回格式化的字符串。

當(dāng)然,還有一個(gè)問(wèn)題,如何將(不同的)值轉(zhuǎn)化為字符串?很幸運(yùn),Python總是把任意值傳入 repr() 或 str() 函數(shù),轉(zhuǎn)為字符串。相對(duì)而言引號(hào)('')等價(jià)于repr(),不過(guò)不提倡這樣用。

函數(shù)str() 用于將值轉(zhuǎn)化為適于人閱讀的形式,而 repr()轉(zhuǎn)化為供解釋器讀取的形式(如果沒(méi)有等價(jià)的語(yǔ)法,則會(huì)發(fā)生SyntaxError 異常) 某對(duì)象沒(méi)有適于人閱讀的解釋形式的話,str()會(huì)返回與repr()等同的值。很多類型,諸如數(shù)值或鏈表、字典這樣的結(jié)構(gòu),針對(duì)各函數(shù)都有著統(tǒng)一的解讀方式。字符串和浮點(diǎn)數(shù),有著獨(dú)特的解讀方式。

以下是一些示例:

>;>;>; s = 'Hello, world.'
>;>;>; str(s)
'Hello, world.'
>;>;>; repr(s)
"'Hello, world.'"
>;>;>; str(0.1)
'0.1'
>;>;>; repr(0.1)
'0.10000000000000001'
>;>;>; x = 10 * 3.25
>;>;>; y = 200 * 200
>;>;>; s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>;>;>; print s
The value of x is 32.5, and y is 40000...
>;>;>; # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>;>;>; hellos = repr(hello)
>;>;>; print hellos
'hello, world\n'
>;>;>; # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
>;>;>; # reverse quotes are convenient in interactive sessions:
... `x, y, ('spam', 'eggs')`
"(32.5, 40000, ('spam', 'eggs'))"
以下兩種方法可以輸出平方和立方表:

>;>;>; import string
>;>;>; for x in range(1, 11):
...     print string.rjust(repr(x), 2), string.rjust(repr(x*x), 3),
...     # Note trailing comma on previous line
...     print string.rjust(repr(x*x*x), 4)
...
1   1    1
2   4    8
3   9   27
4  16   64
5  25  125
6  36  216
7  49  343
8  64  512
9  81  729
10 100 1000
>;>;>; for x in range(1,11):
...     print '%2d %3d %4d' % (x, x*x, x*x*x)
...
1   1    1
2   4    8
3   9   27
4  16   64
5  25  125
6  36  216
7  49  343
8  64  512
9  81  729
10 100 1000
(需要注意的是使用print方法時(shí)每?jī)闪兄g有一個(gè)空格:它總是在參數(shù)之間加一個(gè)空格。)

以上是一個(gè)string.rjust()函數(shù)的演示,這個(gè)函數(shù)把字符串輸出到一列,并通過(guò)向左側(cè)填充空格來(lái)使其右對(duì)齊。類似的函數(shù)還有 string.ljust() 和 string.center()。這些函數(shù)只是輸出新的字符串,并不改變什么。如果輸出的字符串太長(zhǎng),它們也不會(huì)截?cái)嗨窃瓨虞敵,這會(huì)使你的輸出格式變得混亂,不過(guò)總強(qiáng)過(guò)另一種選擇(截?cái)嘧址,因(yàn)槟菢訒?huì)產(chǎn)生錯(cuò)誤的輸出值。(如果你確實(shí)需要截?cái)嗨,可以使用切片操作,例如?quot;string.ljust(x, n)[0]"。)

還有一個(gè)函數(shù),string.zfill()它用于向數(shù)值的字符串表達(dá)左側(cè)填充0。該函數(shù)可以正確理解正負(fù)號(hào):

>;>;>; import string
>;>;>; string.zfill('12', 5)
'00012'
>;>;>; string.zfill('-3.14', 7)
'-003.14'
>;>;>; string.zfill('3.14159265359', 5)
'3.14159265359'
可以如下這樣使用 % 操作符:

>;>;>; import math
>;>;>; print 'The value of PI is approximately %5.3f.' % math.pi
The value of PI is approximately 3.142.
如果有超過(guò)一個(gè)的字符串要格式化為一體,就需要將它們傳入一個(gè)元組做為右值,如下所示:

>;>;>; table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}

>;>;>; for name, phone in table.items():
...     print '%-10s ==>; %10d' % (name, phone)
...
Jack       ==>;       4098
Dcab       ==>;       7678
Sjoerd     ==>;       4127
大多數(shù)類C的格式化操作都需要你傳入適當(dāng)?shù)念愋停贿^(guò)如果你沒(méi)有定義異常,也不會(huì)有什么從內(nèi)核中主動(dòng)的彈出來(lái)。(however, if you don't you get an exception, not a core dump)使用 %s 格式會(huì)更輕松些:如果對(duì)應(yīng)的參數(shù)不是字符串,它會(huì)通過(guò)內(nèi)置的 str() 函數(shù)轉(zhuǎn)化為字符串。Python支持用 * 作為一個(gè)隔離(整型的)參數(shù)來(lái)傳遞寬度或精度。Python不支持C的 %n 和 %p 操作符。

如果可以逐點(diǎn)引用要格式化的變量名,就可以產(chǎn)生符合真實(shí)長(zhǎng)度的格式化字符串,不會(huì)產(chǎn)生間隔。這一效果可以通過(guò)使用 form %(name)結(jié)構(gòu)來(lái)實(shí)現(xiàn):

>;>;>; table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>;>;>; print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table
Jack: 4098; Sjoerd: 4127; Dcab: 8637678
這個(gè)技巧在與新的內(nèi)置函數(shù) vars() 組合使用時(shí)非常有用,該函數(shù)返回一個(gè)包含所有局部變量的字典。

  
7.2 讀寫文件
open()  返回一個(gè)文件對(duì)象 ,通常的用法需要兩個(gè)參數(shù):“open(filename, mode)”。

>;>;>; f=open('/tmp/workfile', 'w')
>;>;>; print f
<open file '/tmp/workfile', mode 'w' at 80a0960>;
第一個(gè)參數(shù)是一個(gè)標(biāo)識(shí)文件名的字符串。第二個(gè)參數(shù)是由有限的字母組成的字符串,描述了文件將會(huì)被如何使用?蛇x的模式有:‘r',此選項(xiàng)使文件只讀;‘w’,此選項(xiàng)使文件只寫(對(duì)于同名文件,該操作使原有文件被覆蓋); ‘a(chǎn)’,此選項(xiàng)以追加方式打開(kāi)文件;‘r+’,此選項(xiàng)以讀寫方式打開(kāi)文件;如果沒(méi)有指定,默認(rèn)為‘r’模式。

在Windows 和 Macintosh平臺(tái)上,‘b’模式以二進(jìn)制方式打開(kāi)文件,所以可能會(huì)有類似于‘rb’,‘wb’,‘r+b’等等模式組合。 Windows平臺(tái)上文本文件與二進(jìn)制文件是有區(qū)別的,讀寫文本文件時(shí),行尾會(huì)自動(dòng)添加行結(jié)束符。這種后臺(tái)操作方式對(duì)文本文件沒(méi)有什么問(wèn)題,但是操作JPEG或EXE這樣的二進(jìn)制文件時(shí)就會(huì)產(chǎn)生破壞。在操作這些文件時(shí)一定要記得以二進(jìn)制模式打開(kāi)。(需要注意的是Mactiontosh平臺(tái)上的文本模式依賴于其使用的底層C庫(kù))。

  
7.2.1 文件對(duì)象(file object)的方法
本節(jié)中的示例都默認(rèn)文件對(duì)象f已經(jīng)創(chuàng)建。

要讀取文件內(nèi)容,需要調(diào)用 f.read(size),該方法讀取若干數(shù)量的數(shù)據(jù)并以字符串形式返回其內(nèi)容,字符串長(zhǎng)度為數(shù)值size所指定的大小。如果沒(méi)有指定size或者指定為負(fù)數(shù),就會(huì)讀取并返回整個(gè)文件。當(dāng)文件大小為當(dāng)前機(jī)器內(nèi)存兩倍時(shí),就會(huì)產(chǎn)生問(wèn)題。正常情況下,會(huì)按size盡可能大的讀取和返回?cái)?shù)據(jù)。如果到了文件末尾,f.read() 會(huì)返回一個(gè)空字符串("")。

>;>;>; f.read()
'This is the entire file.\n'
>;>;>; f.read()
''
f.readline() 從文件中讀取單獨(dú)一行,字符串結(jié)尾會(huì)自動(dòng)加上一個(gè)換行符,只有當(dāng)文件最后一行沒(méi)有以換行符結(jié)尾時(shí),這一操作才會(huì)被忽略。這樣返回值就不會(huì)有什么混淆不清,如果 if f.readline() 返回一個(gè)空字符串,那就表示到達(dá)了文件末尾,如果是一個(gè)空行,就會(huì)描述為‘\n’,一個(gè)只包含換行符的字符串。

>;>;>; f.readline()
'This is the first line of the file.\n'
>;>;>; f.readline()
'Second line of the file\n'
>;>;>; f.readline()
''
f.readlines() 返回一個(gè)列表,其中包含了文件中所有的數(shù)據(jù)行。如果給定了 sizehint 參數(shù),就會(huì)讀入多于一行的比特?cái)?shù),從中返回行列表。這個(gè)功能通常用于高效讀取大型行文件,避免了將整個(gè)文件讀入內(nèi)存。這種操作只返回完整的行。

>;>;>; f.readlines()
['This is the first line of the file.\n', 'Second line of the file\n']
f.write(string) 將 string 的內(nèi)容寫入文件,返回None。

>;>;>; f.write('This is a test\n')
f.tell() 返回一個(gè)整數(shù),代表文件對(duì)象在文件中的指針位置,該數(shù)值計(jì)量了自文件開(kāi)頭到指針處的比特?cái)?shù)。需要改變文件對(duì)象指針話話,使用“f.seek(offset, from_what)” 。指針在該操作中從指定的引用位置移動(dòng) offset 比特,引用位置由 from_what 參數(shù)指定。. from_what 值為0表示自文件起初處開(kāi)始,1表示自當(dāng)前文件指針位置開(kāi)始,2表示自文件末尾開(kāi)始。 from_what 可以乎略,其默認(rèn)值為零,此時(shí)從文件頭開(kāi)始。

>;>;>; f=open('/tmp/workfile', 'r+')
>;>;>; f.write('0123456789abcdef')
>;>;>; f.seek(5)     # Go to the 6th byte in the file
>;>;>; f.read(1)        
'5'
>;>;>; f.seek(-3, 2) # Go to the 3rd byte before the end
>;>;>; f.read(1)
'd'
文件使用完后,調(diào)用 f.close() 可以關(guān)閉文件,釋放打開(kāi)文件后占用的系統(tǒng)資源。調(diào)用 f.close()之后,再調(diào)用文件對(duì)象會(huì)自動(dòng)引發(fā)錯(cuò)誤。

>;>;>; f.close()
>;>;>; f.read()
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
ValueError: I/O operation on closed file
文件對(duì)象還有一些不太常用的附加方法,比如 isatty() 和 truncate() 在庫(kù)參考手冊(cè)中有文件對(duì)象的完整指南。

  
7.2.2 pickle 模塊
  

我們可以很容易的讀寫文件中的字符串。數(shù)值就要多費(fèi)點(diǎn)兒周折,因?yàn)閞ead() 方法只會(huì)返回字符串,應(yīng)該將其傳入string.atoi()方法中,就可以將'123' 這樣的字符轉(zhuǎn)為相應(yīng)的值。不過(guò),當(dāng)你需要保存更為復(fù)雜的數(shù)據(jù)類型,例如鏈表、字典,類的實(shí)例,事情就會(huì)變得更復(fù)雜了。

好在用戶不必要非得自己編寫和調(diào)試保存復(fù)雜數(shù)據(jù)類型的代碼。Python提供了一個(gè)名為 Pickle 的標(biāo)準(zhǔn)模塊。這是一個(gè)令人贊嘆的模塊,幾乎可以把任何Python對(duì)象(甚至是一些Python代碼塊(form)!)表達(dá)為為字符串,這一過(guò)程稱之為封裝 (pickling)。從字符串表達(dá)出重新構(gòu)造對(duì)象稱之為拆封(unpickling)。封裝狀態(tài)中的對(duì)象可以存儲(chǔ)在文件或?qū)ο笾,也可以通過(guò)網(wǎng)絡(luò)在遠(yuǎn)程的機(jī)器之間傳輸。

如果你有一個(gè)對(duì)象x,一個(gè)以寫模式打開(kāi)的文件對(duì)象f,封裝對(duì)像的最簡(jiǎn)單的方法只需要一行代碼:

pickle.dump(x, f)
如果f是一個(gè)以讀模式打開(kāi)的文件對(duì)象,就可以重裝拆封這個(gè)對(duì)象:

x = pickle.load(f)
(如果不想把封裝的數(shù)據(jù)寫入文件,這里還有一些其它的變化可用。完整的pickle文檔請(qǐng)見(jiàn)庫(kù)參考手冊(cè))。

pickle 是存儲(chǔ)Python對(duì)象以供其它程序或其本身以后調(diào)用的標(biāo)準(zhǔn)方法。提供這一組技術(shù)的是一個(gè)持久化對(duì)象( persistent object )。因?yàn)?pickle 的用途很廣泛,很多Python擴(kuò)展的作者都非常注意類似矩陣這樣的新數(shù)據(jù)類型是否適合封裝和拆封
作者: mq110    時(shí)間: 2005-05-31 16:57
標(biāo)題: Python 指南
8. 錯(cuò)誤和異常
至今為止還沒(méi)有進(jìn)一步的談?wù)撨^(guò)錯(cuò)誤信息,不過(guò)在你已經(jīng)試驗(yàn)過(guò)的那些例子中,可能已經(jīng)遇到過(guò)一些。Python中(至少)有兩種錯(cuò)誤:語(yǔ)法錯(cuò)誤和異常( syntax errors and exceptions)。

  
8.1 語(yǔ)法錯(cuò)誤
語(yǔ)法錯(cuò)誤,也稱作解析錯(cuò)誤,可能是學(xué)習(xí)Python的過(guò)程中最容易犯的:

>;>;>; while True print 'Hello world'
  File "<stdin>;", line 1, in ?
    while True print 'Hello world'
                   ^
SyntaxError: invalid syntax
解析器會(huì)重復(fù)出錯(cuò)的行,并在行中最早發(fā)現(xiàn)的錯(cuò)誤位置上顯示一個(gè)小箭頭。錯(cuò)誤(至少是被檢測(cè)到)就發(fā)生在箭頭指向的位置。示例中的錯(cuò)誤表現(xiàn)在關(guān)鍵字print上,因?yàn)樵谒吧倭艘粋(gè)冒號(hào)(:)。同時(shí)也會(huì)顯示文件名和行號(hào),這樣你就可以知道錯(cuò)誤來(lái)自哪個(gè)腳本,什么位置。

  
8.2 異常
即使是在語(yǔ)法上完全正確的語(yǔ)句,嘗試執(zhí)行它的時(shí)候,也有可能會(huì)發(fā)生錯(cuò)誤。在程序運(yùn)行中檢測(cè)出的錯(cuò)誤稱之為異常,它通常不會(huì)導(dǎo)致致命的問(wèn)題,你很快就會(huì)學(xué)到如何在Python程序中控制它們。大多數(shù)異常不會(huì)由程序處理,而是顯示一個(gè)錯(cuò)誤信息:

>;>;>; 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
>;>;>; 4 + spam*3
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
NameError: name 'spam' is not defined
>;>;>; '2' + 2
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
錯(cuò)誤信息的最后一行指出發(fā)生了什么錯(cuò)誤。異常也有不同的類型,異常類型做為錯(cuò)誤信息的一部分顯示出來(lái):示例中的異常分別為零除錯(cuò)誤( ZeroDivisionError ),命名錯(cuò)誤( NameError)和類型錯(cuò)誤( TypeError )。打印錯(cuò)誤信息時(shí),異常的類型作為異常的內(nèi)置名顯示。對(duì)于所有的內(nèi)置異常都是如此,不過(guò)用戶自定義異常就不一定了(盡管這是一個(gè)很有用的約定)。標(biāo)準(zhǔn)異常名是內(nèi)置的標(biāo)識(shí)(沒(méi)有保留關(guān)鍵字)。

這一行后一部分是關(guān)于該異常類型的詳細(xì)說(shuō)明,這意味著它的內(nèi)容依賴于異常類型。

錯(cuò)誤信息的前半部分以堆棧的形式列出異常發(fā)生的位置。通常在堆棧中列出了源代碼行,然而,來(lái)自標(biāo)準(zhǔn)輸入的源碼不會(huì)顯示出來(lái)。

Python 庫(kù)參考手冊(cè) 列出了內(nèi)置異常和它們的含義。

  
8.3 處理異常
通過(guò)編程可以處理指定的異常。以下的例子重復(fù)要求用戶輸入一個(gè)值,直到用戶輸入的是一個(gè)合法的整數(shù)為止。不過(guò)這個(gè)程序允許用戶中斷程序(使用 Control-C 或者其它操作系統(tǒng)支持的方法)。需要注意的是用戶發(fā)出的中斷會(huì)引發(fā)一個(gè) KeyboardInterrupt 異常。

>;>;>; while True:
...     try:
...         x = int(raw_input("lease enter a number: ")
...         break
...     except ValueError:
...         print "Oops! That was no valid number.  Try again..."
...
try 語(yǔ)句按如下方式工作:

首先,執(zhí)行 try 子句(在try 和 except關(guān)鍵字之間的部分)。

如果沒(méi)有異常發(fā)生,except 子句 在try語(yǔ)句執(zhí)行完畢后就被忽略了。

如果在try子句執(zhí)行過(guò)程中發(fā)生了異常,那么該子句其余的部分就會(huì)被忽略。如果異常匹配于except關(guān)鍵字后面指定的異常類型,就執(zhí)行對(duì)應(yīng)的except子句,忽略try子句的其它部分。然后繼續(xù)執(zhí)行try語(yǔ)句之后的代碼。

如果發(fā)生了一個(gè)異常,在except子句中沒(méi)有與之匹配的分支,它就會(huì)傳遞到上一級(jí)try語(yǔ)句中。如果最終仍找不到對(duì)應(yīng)的處理語(yǔ)句,它就成為一個(gè)未處理異常,終止程序運(yùn)行,顯示提示信息。

一個(gè)try 語(yǔ)句可能包含多個(gè) except 子句,分別指定處理不同的異常。至多只會(huì)有一個(gè)分支被執(zhí)行。異常處理程序只會(huì)處理對(duì)應(yīng)的try子句中發(fā)生的異常,在同一個(gè)try語(yǔ)句中,其他子句中發(fā)生的異常則不作處理。一個(gè)except子句可以在括號(hào)中列出多個(gè)異常的名字,例如:

... except (RuntimeError, TypeError, NameError):
...     pass
最后一個(gè)except子句可以省略異常名,把它當(dāng)做一個(gè)通配項(xiàng)使用。一定要慎用這種方法,因?yàn)樗芸赡軙?huì)屏蔽掉真正的程序錯(cuò)誤,使人無(wú)法發(fā)現(xiàn)!它也可以用于打印一行錯(cuò)誤信息,然后重新拋出異常(可以使調(diào)用者更好的處理異常)。

import string, sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(string.strip(s))
except IOError, (errno, strerror):
    print "I/O error(%s): %s" % (errno, strerror)
except ValueError:
    print "Could not convert data to an integer."
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
try ... except 語(yǔ)句可以帶有一個(gè) else 子句, 該子句只能出現(xiàn)在所有except子句之后。當(dāng)try語(yǔ)句沒(méi)有拋出異常時(shí),需要執(zhí)行一些代碼,可以使用這個(gè)子句。例如:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()
使用 else 子句比在 try 子句中附加代碼要好,因?yàn)檫@樣可以避免 try ... except 意外的截獲本來(lái)不屬于它們保護(hù)的那些代碼拋出的異常。

發(fā)生異常時(shí),可能會(huì)有一個(gè)附屬值,作為異常的參數(shù)存在。這個(gè)參數(shù)是否存在、是什么類型,依賴于異常的類型。

在異常名(列表)之后,也可以為 except 子句指定一個(gè)變量。這個(gè)變量綁定于一個(gè)異常實(shí)例,它存儲(chǔ)在 instance.args 的參數(shù)中。為了方便起見(jiàn),異常實(shí)例定義了 __getitem__ 和 __str__ ,這樣就可以直接訪問(wèn)過(guò)打印參數(shù)而不必引用 .args。

>;>;>; try:
...    raise Exception('spam', 'eggs')
... except Exception, inst:
...    print type(inst)     # the exception instance
...    print inst.args      # arguments stored in .args
...    print inst           # __str__ allows args to printed directly
...    x, y = inst          # __getitem__ allows args to be unpacked directly
...    print 'x =', x
...    print 'y =', y
...
<type 'instance'>;
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
對(duì)于未處理的異常,如果它有一個(gè)參數(shù),那做就會(huì)作為錯(cuò)誤信息的最后一部分(“明細(xì)”)打印出來(lái)。

異常處理句柄不止可以處理直接發(fā)生在try子句中的異常,即使是其中(甚至是間接)調(diào)用的函數(shù),發(fā)生了異常,也一樣可以處理。例如:

>;>;>; def this_fails():
...     x = 1/0
...
>;>;>; try:
...     this_fails()
... except ZeroDivisionError, detail:
...     print 'Handling run-time error:', detail
...
Handling run-time error: integer division or modulo
  
8.4 拋出異常
在發(fā)生了特定的異常時(shí),程序員可以用 raise 語(yǔ)句強(qiáng)制拋出異常。例如:

>;>;>; raise NameError, 'HiThere'
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
NameError: HiThere
第一個(gè)參數(shù)指定了所拋出異常的名稱,第二個(gè)指定了異常的參數(shù)。

如果你決定拋出一個(gè)異常而不處理它,raise 語(yǔ)句可以讓你很簡(jiǎn)單的重新拋出該異常。

>;>;>; try:
...     raise NameError, 'HiThere'
... except NameError:
...     print 'An exception flew by!'
...     raise
...
An exception flew by!
Traceback (most recent call last):
  File "<stdin>;", line 2, in ?
NameError: HiThere
  
8.5 用戶自定義異常
在程序中可以通過(guò)創(chuàng)建新的異常類型來(lái)命名自己的異常。異常類通常應(yīng)該直接或間接的從 Exception 類派生,例如:

>;>;>; class MyError(Exception):
...     def __init__(self, value):
...         self.value = value
...     def __str__(self):
...         return repr(self.value)
...
>;>;>; try:
...     raise MyError(2*2)
... except MyError, e:
...     print 'My exception occurred, value:', e.value
...
My exception occurred, value: 4
>;>;>; raise MyError, 'oops!'
Traceback (most recent call last):
  File "<stdin>;", line 1, in ?
__main__.MyError: 'oops!'
異常類中可以定義任何其它類中可以定義的東西,但是通常為了保持簡(jiǎn)單,只在其中加入幾個(gè)屬性信息,以供異常處理句柄提取。如果一個(gè)新創(chuàng)建的模塊中需要拋出幾種不同的錯(cuò)誤時(shí),一個(gè)通常的作法是為該模塊定義一個(gè)異常基類,然后針對(duì)不同的錯(cuò)誤類型派生出對(duì)應(yīng)的異常子類。

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message
與標(biāo)準(zhǔn)異常相似,大多數(shù)異常的命名都以“Error”結(jié)尾。

很多標(biāo)準(zhǔn)模塊中都定義了自己的異常,用以報(bào)告在他們所定義的函數(shù)中可能發(fā)生的錯(cuò)誤。關(guān)于類的進(jìn)一步信息請(qǐng)參見(jiàn)第 9章,“類”。

  
8.6 定義清理行為
try 語(yǔ)句還有另一個(gè)可選的子句,目的在于定義在任何情況下都一定要執(zhí)行的功能。例如:

>;>;>; try:
...     raise KeyboardInterrupt
... finally:
...     print 'Goodbye, world!'
...
Goodbye, world!
Traceback (most recent call last):
  File "<stdin>;", line 2, in ?
KeyboardInterrupt
不管try子句中有沒(méi)有發(fā)生異常, finally 子句都一定會(huì)被執(zhí)行。如果發(fā)生異常,在finally子句執(zhí)行完后它會(huì)被重新拋出。 try 子句經(jīng)由 break 或 return 退出也一樣會(huì)執(zhí)行finally 子句。

在finally 子句中的代碼用于釋放外部資源(例如文件或網(wǎng)絡(luò)連接),不管這些資源是否已經(jīng)成功利用。

在 try 語(yǔ)句中可以使用若干個(gè) except 子句或一個(gè) finally 子句,但兩者不能共存。
作者: mq110    時(shí)間: 2005-05-31 16:57
標(biāo)題: Python 指南
9. 類
Python在盡可能不增加新的語(yǔ)法和語(yǔ)義的情況下加入了類機(jī)制。這種機(jī)制是C++和Python's Modula-3的混合。Python中的類沒(méi)有在用戶和定義之間建立一個(gè)絕對(duì)的屏障,而是依賴于用戶自覺(jué)的不去“破壞定義”。然而,類機(jī)制最重要的功能都完整的保留下來(lái)。類繼承機(jī)制允許多繼承,派生類可以覆蓋(override)基類中的任何方法,方法中可以調(diào)用基類中的同名方法。對(duì)象可以包含任意數(shù)量的私有成員。

用C++術(shù)語(yǔ)來(lái)講,所有的類成員(包括數(shù)據(jù)成員)都是公有(public)的,所有的成員函數(shù)都是虛擬(virtual)的。用Modula-3的術(shù)語(yǔ)來(lái)講,在成員方法中沒(méi)有什么簡(jiǎn)便的方式(shorthands)可以引用對(duì)象的成員:方法函數(shù)在定義時(shí)需要以引用的對(duì)象做為第一個(gè)參數(shù),以調(diào)用時(shí)則會(huì)隱式引用對(duì)象。這樣就形成了語(yǔ)義上的引入和重命名。( This provides semantics for importing and renaming. )但是,像C++而非Modula-3中那樣,大多數(shù)帶有特殊語(yǔ)法的內(nèi)置操作符(算法運(yùn)算符、下標(biāo)等)都可以針對(duì)類的需要重新定義。

  
9.1 有關(guān)術(shù)語(yǔ)的話題
由于沒(méi)有什么關(guān)于類的通用術(shù)語(yǔ),我從Smalltalk和C++中借用一些(我更希望用Modula-3的,因?yàn)樗拿嫦驅(qū)ο髾C(jī)制比C++更接近Python,不過(guò)我想沒(méi)多少讀者聽(tīng)說(shuō)過(guò)它)。

我要提醒讀者,這里有一個(gè)面向?qū)ο蠓矫娴男g(shù)語(yǔ)陷阱,在Python中“對(duì)象”這個(gè)詞不一定指類實(shí)例。Python中并非所有的類型都是類:例如整型、鏈表這些內(nèi)置數(shù)據(jù)類型就不是,甚至某些像文件這樣的外部類型也不是,這一點(diǎn)類似于C++和Modula-3,而不像Smalltalk。然而,所有的Python類型在語(yǔ)義上都有一點(diǎn)相同之處:描述它們的最貼切詞語(yǔ)是“對(duì)象”。

對(duì)象是被特化的,多個(gè)名字(在多個(gè)作用域中)可以綁定同一個(gè)對(duì)象。這相當(dāng)于其它語(yǔ)言中的別名。通常對(duì)Python的第一印象中會(huì)忽略這一點(diǎn),使用那些不可變的基本類型(數(shù)值、字符串、元組)時(shí)也可以很放心的忽視它。然而,在Python代碼調(diào)用字典、鏈表之類可變對(duì)象,以及大多數(shù)涉及程序外部實(shí)體(文件、窗體等等)的類型時(shí),這一語(yǔ)義就會(huì)有影響。這通用有助于優(yōu)化程序,因?yàn)閯e名的行為在某些方面類似于指針。例如,很容易傳遞一個(gè)對(duì)象,因?yàn)樵谛袨樯现皇莻鬟f了一個(gè)指針。如果函數(shù)修改了一個(gè)通過(guò)參數(shù)傳遞的對(duì)象,調(diào)用者可以接收到變化--在Pascal中這需要兩個(gè)不同的參數(shù)傳遞機(jī)制。

  
9.2 Python 作用域和命名空間
在介紹類之前,我首先介紹一些有關(guān)Python作用域的規(guī)則:類的定義非常巧妙的運(yùn)用了命名空間,要完全理解接下來(lái)的知識(shí),需要先理解作用域和命名空間的工作原理。另外,這一切的知識(shí)對(duì)于任何高級(jí)Python程序員都非常有用。

我們從一些定義開(kāi)始。

命名空間是從命名到對(duì)象的映射。當(dāng)前命名空間主要是通過(guò)Python字典實(shí)現(xiàn)的,不過(guò)通常不關(guān)心具體的實(shí)現(xiàn)方式(除非出于性能考慮),以后也有可能會(huì)改變其實(shí)現(xiàn)方式。以下有一些命名空間的例子:內(nèi)置命名(像 abs() 這樣的函數(shù),以及內(nèi)置異常名)集,模塊中的全局命名,函數(shù)調(diào)用中的局部命名。某種意義上講對(duì)象的屬性集也是一個(gè)命名空間。關(guān)于命名空間需要了解的一件很重要的事就是不同命名空間中的命名沒(méi)有任何聯(lián)系,例如兩個(gè)不同的模塊可能都會(huì)定義一個(gè)名為“maximize”的函數(shù)而不會(huì)發(fā)生混淆--用戶必須以模塊名為前綴來(lái)引用它們。

順便提一句,我稱Python中任何一個(gè)“.”之后的命名為屬性--例如,表達(dá)式z.real中的real是對(duì)象z的一個(gè)屬性。嚴(yán)格來(lái)講,從模塊中引用命名是引用屬性:表達(dá)式 modname.funcname中,modname 是一個(gè)模塊對(duì)象, funcname 是它的一個(gè)屬性。因此,模塊的屬性和模塊中的全局命名有直接的映射關(guān)系:它們共享同一命名空間! 9.1

屬性可以是只讀過(guò)或?qū)懙。后一種情況下,可以對(duì)屬性賦值。你可以這樣作:“modname.the_answer = 42”?蓪懙膶傩砸部梢杂胐el語(yǔ)句刪除。例如:“del modname.the_answer”會(huì)從 modname對(duì)象中刪除the_answer 屬性。

不同的命名空間在不同的時(shí)刻創(chuàng)建,有不同的生存期。包含內(nèi)置命名的命名空間在Python解釋器啟動(dòng)時(shí)創(chuàng)建,會(huì)一直保留,不被刪除。模塊的全局命名空間在模塊定義被讀入時(shí)創(chuàng)建,通常,模塊命名空間也會(huì)一直保存到解釋器退出。由解釋器在最高層調(diào)用執(zhí)行的語(yǔ)句,不管它是從腳本文件中讀入還是來(lái)自交互式輸入,都是__main__模塊的一部分,所以它們也擁有自己的命名空間。(內(nèi)置命名也同樣被包含在一個(gè)模塊中,它被稱作__builtin__。)

當(dāng)函數(shù)被調(diào)用時(shí)創(chuàng)建一個(gè)局部命名空間,函數(shù)反正返回過(guò)拋出一個(gè)未在函數(shù)內(nèi)處理的異常時(shí)刪除。(實(shí)際上,說(shuō)是遺忘更為貼切)。當(dāng)然,每一個(gè)遞歸調(diào)用擁有自己的命名空間。

作用域是指Python程序可以直接訪問(wèn)到的命名空間!爸苯釉L問(wèn)”在這里意味著訪問(wèn)命名空間中的命名時(shí)無(wú)需加入附加的修飾符。

盡管作用域是靜態(tài)定義,在使用時(shí)他們都是動(dòng)態(tài)的。每次執(zhí)行時(shí),至少有三個(gè)命名空間可以直接訪問(wèn)的作用域嵌套在一起:包含局部命名的使用域在最里面,首先被搜索;其次搜索的是中層的作用域,這里包含了同級(jí)的函數(shù);最后搜索最外面的作用域,它包含內(nèi)置命名。

如果一個(gè)命名聲明為全局的,那么所有的賦值和引用都直接針對(duì)包含模全局命名的中級(jí)作用域。另外,從外部訪問(wèn)到的所有內(nèi)層作用域的變量都是只讀的。

從文本意義上講,局部作用域引用當(dāng)前函數(shù)的命名。在函數(shù)之外,局部作用域與全局使用域引用同一命名空間:模塊命名空間。類定義也是局部作用域中的另一個(gè)命名空間。

作用域決定于源程序的文本:一個(gè)定義于某模塊中的函數(shù)的全局作用域是該模塊的命名空間,而不是該函數(shù)的別名被定義或調(diào)用的位置,了解這一點(diǎn)非常重要。另一方面,命名的實(shí)際搜索過(guò)程是動(dòng)態(tài)的,在運(yùn)行時(shí)確定的——然而,Python語(yǔ)言也在不斷發(fā)展,以后有可能會(huì)成為靜態(tài)的“編譯”時(shí)確定,所以不要依賴于動(dòng)態(tài)解析。ㄊ聦(shí)上,局部變量已經(jīng)是靜態(tài)確定了。)

Python的一個(gè)特別之處在于其賦值操作總是在最里層的作用域。賦值不會(huì)復(fù)制數(shù)據(jù)——只是將命名綁定到對(duì)象。刪除也是如此:“del x ”只是從局部作用域的命名空間中刪除命名x。事實(shí)上,所有引入新命名的操作都作用于局部作用域。特別是import語(yǔ)句和函數(shù)定將模塊名或函數(shù)綁定于局部作用域。(可以使用global語(yǔ)句將變量引入到全局作用域。)

  
9.3 初識(shí)類
類引入了一點(diǎn)新的語(yǔ)法,三種新的對(duì)象類型,以及一些新的語(yǔ)義。

  
9.3.1 類定義語(yǔ)法
最簡(jiǎn)單的類定義形式如下:

class ClassName:
    <statement-1>;
    .
    .
    .
    <statement-N>;
類的定義就像函數(shù)定義(def語(yǔ)句),要先執(zhí)行才能生效。(你當(dāng)然可以把它放進(jìn)if語(yǔ)句的某一分支,或者一個(gè)函數(shù)的內(nèi)部。)

習(xí)慣上,類定義語(yǔ)句的內(nèi)容通常是函數(shù)定義,不過(guò)其它語(yǔ)句也可以,有時(shí)會(huì)很有用——后面我們?cè)倩剡^(guò)頭來(lái)討論。類中的函數(shù)定義通常包括了一個(gè)特殊形式的參數(shù)列表,用于方法調(diào)用約定——同樣我們?cè)诤竺嬗懻撨@些。

定義一個(gè)類的時(shí)候,會(huì)創(chuàng)建一個(gè)新的命名空間,將其作為局部作用域使用——因此,所以對(duì)局部變量的賦值都引入新的命名空間。特別是函數(shù)定義將新函數(shù)的命名綁定于此。

類定義完成時(shí)(正常退出),就創(chuàng)建了一個(gè)類對(duì)象;旧纤菍(duì)類定義創(chuàng)建的命名空間進(jìn)行了一個(gè)包裝;我們?cè)谙乱还?jié)進(jìn)一步學(xué)習(xí)類對(duì)象的知識(shí)。原始的局部作用域(類定義引入之前生效的那個(gè))得到恢復(fù),類對(duì)象在這里綁定到類定義頭部的類名(例子中是ClassName)。

  
9.3.2 類對(duì)象
類對(duì)象支持兩種操作:屬性引用和實(shí)例化。

屬性引用使用和Python中所有的屬性引用一樣的標(biāo)準(zhǔn)語(yǔ)法: obj.name。類對(duì)象創(chuàng)建后,類命名空間中所有的命名都是有效屬性名。所以如果類定義是這樣:

class MyClass:
    "A simple example class"
    i = 12345
    def f(self):
        return 'hello world'
那么 MyClass.i 和 MyClass.f 是有效的屬性引用,分別返回一個(gè)整數(shù)和一個(gè)方法對(duì)象。也可以對(duì)類屬性賦值,你可以通過(guò)給 MyClass.i 賦值來(lái)修改它。 __doc__ 也是一個(gè)有效的屬性,返回類的文檔字符串:“A simple example class”。

類的實(shí)例化使用函數(shù)符號(hào)。只要將類對(duì)象看作是一個(gè)返回新的類實(shí)例的無(wú)參數(shù)函數(shù)即可。例如(假設(shè)沿用前面的類):

x = MyClass()
以上創(chuàng)建了一個(gè)新的類實(shí)例并將該對(duì)象賦給局部變量x。

這個(gè)實(shí)例化操作(“調(diào)用”一個(gè)類對(duì)象)來(lái)創(chuàng)建一個(gè)空的對(duì)象。很多類都傾向于將對(duì)象創(chuàng)建為有初始狀態(tài)的。因此類可能會(huì)定義一個(gè)名為_(kāi)_init__() 的特殊方法,像下面這樣:

    def __init__(self):
        self.data = []
類定義了 __init__() 方法的話,類的實(shí)例化操作會(huì)自動(dòng)為新創(chuàng)建的類實(shí)例調(diào)用 __init__() 方法。所以在下例中,可以這樣創(chuàng)建一個(gè)新的實(shí)例:

x = MyClass()
當(dāng)然,出于彈性的需要, __init__() 方法可以有參數(shù)。事實(shí)上,參數(shù)通過(guò) __init__()傳遞到類的實(shí)例化操作上。例如:

>;>;>; class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>;>;>; x = Complex(3.0, -4.5)
>;>;>; x.r, x.i
(3.0, -4.5)
  
9.3.3 實(shí)例對(duì)象
現(xiàn)在我們可以用實(shí)例對(duì)象作什么?實(shí)例對(duì)象唯一可用的操作就是屬性引用。有兩種有效的屬性名。

第一種稱作數(shù)據(jù)屬性。這相當(dāng)于Smalltalk中的“實(shí)例變量”或C++中的“數(shù)據(jù)成員”。和局部變量一樣,數(shù)據(jù)屬性不需要聲明,第一次使用時(shí)它們就會(huì)生成。例如,如果x是前面創(chuàng)建的MyClass 實(shí)例,下面這段代碼會(huì)打印出16而不會(huì)有任何多余的殘留:

x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print x.counter
del x.counter
第二種為實(shí)例對(duì)象所接受的引用屬性是方法。方法是屬于一個(gè)對(duì)象的函數(shù)。(在Python中,方法不止是類實(shí)例所獨(dú)有:其它類型的對(duì)象也可有方法。例如,鏈表對(duì)象有append,insert,remove,sort等等方法。然而,在這里,除非特別說(shuō)明,我們提到的方法特指類方法)

實(shí)例對(duì)象的有效名稱依賴于它的類。按照定義,類中所有(用戶定義)的函數(shù)對(duì)象對(duì)應(yīng)它的實(shí)例中的方法。所以在我們的例子中,x..f是一個(gè)有效的方法引用,因?yàn)镸yClass.f是一個(gè)函數(shù)。但x.i不是,因?yàn)镸yClass.i是不是函數(shù)。不過(guò)x.f和MyClass.f不同--它是一個(gè)  方法對(duì)象,不是一個(gè)函數(shù)對(duì)象。

  
9.3.4 方法對(duì)象
通常方法是直接調(diào)用的:

x.f()
在我們的例子中,這會(huì)返回字符串‘hello world’。然而,也不是一定要直接調(diào)用方法。x.f是一個(gè)方法對(duì)象,它可以存儲(chǔ)起來(lái)以后調(diào)用。例如:

xf = x.f
while True:
    print xf()
會(huì)不斷的打印“Hello world”。

調(diào)用方法時(shí)發(fā)生了什么?你可能注意到調(diào)用 x.f() 時(shí)沒(méi)有引用前面標(biāo)出的變量,盡管在f的函數(shù)定義中指明了一個(gè)參數(shù)。這個(gè)參數(shù)怎么了?事實(shí)上如果函數(shù)調(diào)用中缺少參數(shù),Python會(huì)拋出異常--甚至這個(gè)參數(shù)實(shí)際上沒(méi)什么用……

實(shí)際上,你可能已經(jīng)猜到了答案:方法的特別之處在于實(shí)例對(duì)象作為函數(shù)的第一個(gè)參數(shù)傳給了函數(shù)。在我們的例子中,調(diào)用x.f() 相當(dāng)于MyClass.f(x)。通常,以n個(gè)參數(shù)的列表去調(diào)用一個(gè)方法就相當(dāng)于將方法的對(duì)象插入到參數(shù)列表的最前面后,以這個(gè)列表去調(diào)用相應(yīng)的函數(shù)。

如果你還是不理解方法的工作原理,了解一下它的實(shí)現(xiàn)也許有幫助。引用非數(shù)據(jù)屬性的實(shí)例屬性時(shí),會(huì)搜索它的類。如果這個(gè)命名確認(rèn)為一個(gè)有效的函數(shù)對(duì)象類屬性,就會(huì)將實(shí)例對(duì)象和函數(shù)對(duì)象封裝進(jìn)一個(gè)抽象對(duì)象:這就是方法對(duì)象。以一個(gè)參數(shù)列表調(diào)用方法對(duì)象時(shí),它被重新拆封,用實(shí)例對(duì)象和原始的參數(shù)列表構(gòu)造一個(gè)新的參數(shù)列表,然后函數(shù)對(duì)象調(diào)用這個(gè)新的參數(shù)列表。

  
9.4 一些說(shuō)明
〔有些內(nèi)容可能需要明確一下……〕

同名的數(shù)據(jù)屬性會(huì)覆蓋方法屬性,為了避免可能的命名沖突--這在大型程序中可能會(huì)導(dǎo)致難以發(fā)現(xiàn)的bug--最好以某種命名約定來(lái)避免沖突?蛇x的約定包括方法的首字母大寫,數(shù)據(jù)屬性名前綴小寫(可能只是一個(gè)下劃線),或者方法使用動(dòng)詞而數(shù)據(jù)屬性使用名詞。

數(shù)據(jù)屬性可以由方法引用,也可以由普通用戶(客戶)調(diào)用。換句話說(shuō),類不能實(shí)現(xiàn)純的數(shù)據(jù)類型。事實(shí)上,Python中沒(méi)有什么辦法可以強(qiáng)制隱藏?cái)?shù)據(jù)--一切都基本約定的慣例。(另一方法講,Python的實(shí)現(xiàn)是用C寫成的,如果有必要,可以用C來(lái)編寫Python擴(kuò)展,完全隱藏實(shí)現(xiàn)的細(xì)節(jié),控制對(duì)象的訪問(wèn)。)

客戶應(yīng)該小心使用數(shù)據(jù)屬性--客戶可能會(huì)因?yàn)殡S意修改數(shù)據(jù)屬性而破壞了本來(lái)由方法維護(hù)的數(shù)據(jù)一致性。需要注意的是,客戶只要注意避免命名沖突,就可以隨意向?qū)嵗刑砑訑?shù)據(jù)屬性而不會(huì)影響方法的有效性--再次強(qiáng)調(diào),命名約定可以省去很多麻煩。

從方法內(nèi)部引用數(shù)據(jù)屬性(以及其它方法。](méi)有什么快捷的方式。我認(rèn)為這事實(shí)上增加了方法的可讀性:即使粗略的瀏覽一個(gè)方法,也不會(huì)有混淆局部變量和實(shí)例變量的機(jī)會(huì)。

習(xí)慣上,方法的第一個(gè)參數(shù)命名為 self。這僅僅是一個(gè)約定:對(duì)Python而言,self 絕對(duì)沒(méi)有任何特殊含義。(然而要注意的是,如果不遵守這個(gè)約定,別的Python程序員閱讀你的代碼時(shí)會(huì)有不便,而且有些類瀏覽程序也是遵循此約定開(kāi)發(fā)的。)

類屬性中的任何函數(shù)對(duì)象在類實(shí)例中都定義為方法。不是必須要將函數(shù)定義代碼寫進(jìn)類定義中,也可以將一個(gè)函數(shù)對(duì)象賦給類中的一個(gè)變量。例如:

# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1
    def g(self):
        return 'hello world'
    h = g
現(xiàn)在 f, g 和 h 都是類C的屬性,引用的都是函數(shù)對(duì)象,因此它們都是C實(shí)例的方法--h(huán)嚴(yán)格等于g。要注意的是這種習(xí)慣通常只會(huì)迷惑程序的讀者。

通過(guò) self 參數(shù)的方法屬性,方法可以調(diào)用其它的方法:

class Bag:
    def __init__(self):
        self.data = []
    def add(self, x):
        self.data.append(x)
    def addtwice(self, x):
        self.add(x)
        self.add(x)
方法可以像引用普通的函數(shù)那樣引用全局命名。與方法關(guān)聯(lián)的全局作用域是包含類定義的模塊。(類本身永遠(yuǎn)不會(huì)做為全局作用域使用。┍M管很少有好的理由在方法中使用全局?jǐn)?shù)據(jù),全局作用域確有很多合法的用途:其一是方法可以調(diào)用導(dǎo)入全局作用域的函數(shù)和方法,也可以調(diào)用定義在其中的類和函數(shù)。通常,包含此方法的類也會(huì)定義在這個(gè)全局作用域,在下一節(jié)我們會(huì)了解為何一個(gè)方法要引用自己的類!

  
9.5 繼承
當(dāng)然,如果一種語(yǔ)言不支持繼承就,“類”就沒(méi)有什么意義。派生類的定義如下所示:

class DerivedClassName(BaseClassName):
    <statement-1>;
    .
    .
    .
    <statement-N>;
命名 BaseClassName (示例中的基類名)必須與派生類定義在一個(gè)作用域內(nèi)。除了類,還可以用表達(dá)式,基類定義在另一個(gè)模塊中時(shí)這一點(diǎn)非常有用:

class DerivedClassName(modname.BaseClassName):
派生類定義的執(zhí)行過(guò)程和基類是一樣的。構(gòu)造派生類對(duì)象時(shí),就記住了基類。這在解析屬性引用的時(shí)候尤其有用:如果在類中找不到請(qǐng)求調(diào)用的屬性,就搜索基類。如果基類是由別的類派生而來(lái),這個(gè)規(guī)則會(huì)遞歸的應(yīng)用上去。

派生類的實(shí)例化沒(méi)有什么特殊之處:DerivedClassName() (示列中的派生類)創(chuàng)建一個(gè)新的類實(shí)例。方法引用按如下規(guī)則解析:搜索對(duì)應(yīng)的類屬性,必要時(shí)沿基類鏈逐級(jí)搜索,如果找到了函數(shù)對(duì)象這個(gè)方法引用就是合法的。

派生類可能會(huì)覆蓋其基類的方法。因?yàn)榉椒ㄕ{(diào)用同一個(gè)對(duì)象中的其它方法時(shí)沒(méi)有特權(quán),基類的方法調(diào)用同一個(gè)基類的方法時(shí),可能實(shí)際上最終調(diào)用了派生類中的覆蓋方法。(對(duì)于C++程序員來(lái)說(shuō),Python中的所有方法本質(zhì)上都是虛方法。)

派生類中的覆蓋方法可能是想要擴(kuò)充而不是簡(jiǎn)單的替代基類中的重名方法。有一個(gè)簡(jiǎn)單的方法可以直接調(diào)用基類方法,只要調(diào)用:“BaseClassName.methodname(self, arguments)”。有時(shí)這對(duì)于客戶也很有用。(要注意的中只有基類在同一全局作用域定義或?qū)霑r(shí)才能這樣用。)

  
9.5.1 多繼承
Python同樣有限的支持多繼承形式。多繼承的類定義形如下例:

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>;
    .
    .
    .
    <statement-N>;
這里唯一需要解釋的語(yǔ)義是解析類屬性的規(guī)則。順序是深度優(yōu)先,從左到右。因此,如果在 DerivedClassName (示例中的派生類)中沒(méi)有找到某個(gè)屬性,就會(huì)搜索 Base1 ,然后(遞歸的)搜索其基類,如果最終沒(méi)有找到,就搜索 Base2,以此類推。

(有些人認(rèn)為廣度優(yōu)先--在搜索Base1的基類之前搜索Base2和Base3--看起來(lái)更為自然。然而,如果Base1和Base2之間發(fā)生了命名沖突,你需要了解這個(gè)屬性是定義于Base1還是Base1的基類中。而深度優(yōu)先不區(qū)分屬性繼承自基類還是直接定義。)

顯然不加限制的使用多繼承會(huì)帶來(lái)維護(hù)上的噩夢(mèng),因?yàn)镻ython中只依靠約定來(lái)避免命名沖突。多繼承一個(gè)很有名的問(wèn)題是派生繼承的兩個(gè)基類都是從同一個(gè)基類繼承而來(lái)。目前還不清楚這在語(yǔ)義上有什么意義,然而很容易想到這會(huì)造成什么后果(實(shí)例會(huì)有一個(gè)獨(dú)立的“實(shí)例變量”或數(shù)據(jù)屬性復(fù)本作用于公共基類。)

  
9.6 私有變量
Python對(duì)類的私有成員提供了有限的支持。任何形如__spam (以至少雙下劃線開(kāi)頭,至多單下劃線結(jié)尾)隨即都被替代為 _classname__spam,去掉前導(dǎo)下劃線的classname 即當(dāng)前的類名。這種混淆不關(guān)心標(biāo)識(shí)符的語(yǔ)法位置,所以可用來(lái)定義私有類實(shí)例和類變量、方法,以及全局變量,甚至于將其它類的實(shí)例保存為私有變量;煜L(zhǎng)度超過(guò)255個(gè)字符的時(shí)候可能會(huì)發(fā)生截?cái)。在類的外部,或類名只包含下劃線時(shí),不會(huì)發(fā)生截?cái)唷?br />
命名混淆意在給出一個(gè)在類中定義“私有”實(shí)例變量和方法的簡(jiǎn)單途徑,避免派生類的實(shí)例變量定義產(chǎn)生問(wèn)題,或者與外界代碼中的變量搞混。要注意的是混淆規(guī)則主要目的在于避免意外錯(cuò)誤,被認(rèn)作為私有的變量仍然有可能被訪問(wèn)或修改。在特定的場(chǎng)合它也是有用的,比如調(diào)試的時(shí)候,這也是一直沒(méi)有堵上這個(gè)漏洞的原因之一(小漏洞:派生類和基類取相同的名字就可以使用基類的私有變量。)

要注意的是傳入exec,eval()或evalfile()的代碼不會(huì)將調(diào)用它們的類視作當(dāng)前類,這與global語(yǔ)句的情況類似,global的作用局限于“同一批”進(jìn)行字節(jié)編譯的代碼。同樣的限制也適用于getattr() ,setattr()和delattr(),以及直接引用__dict__的時(shí)候。

  
9.7 補(bǔ)充
有時(shí)類似于Pascal中“記錄(record)”或C中“結(jié)構(gòu)(struct)”的數(shù)據(jù)類型很有用,它將一組已命名的數(shù)據(jù)項(xiàng)綁定在一起。一個(gè)空的類定義可以很好的實(shí)現(xiàn)這它:

class Employee:
    pass

john = Employee() # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
某一段Python代碼需要一個(gè)特殊的抽象數(shù)據(jù)結(jié)構(gòu)的話,通?梢詡魅胍粋(gè)類,事實(shí)上這模仿了該類的方法。例如,如果你有一個(gè)用于從文件對(duì)象中格式化數(shù)據(jù)的函數(shù),你可以定義一個(gè)帶有Read()和Readline()方法的類,以此從字符串緩沖讀取數(shù)據(jù),然后將該類的對(duì)象作為參數(shù)傳入前述的函數(shù)。

實(shí)例方法對(duì)象也有屬性: m.im_self 是一個(gè)實(shí)例方法所屬的對(duì)象,而 m.im_func 是這個(gè)方法對(duì)應(yīng)的函數(shù)對(duì)象。

  
9.8 異常也是類
用戶自定義異常也可以是類。利用這個(gè)機(jī)制可以創(chuàng)建可擴(kuò)展的異常體系。

以下是兩種新的有效(語(yǔ)義上的)異常拋出形式:

raise Class, instance

raise instance
第一種形式中,instance 必須是 Class 或其派生類的一個(gè)實(shí)例。第二種形式是以下形式的簡(jiǎn)寫:

raise instance.__class__, instance
發(fā)生的異常其類型如果是異常子句中列出的類,或者是其派生類,那么它們就是相符的(反過(guò)來(lái)說(shuō)--發(fā)生的異常其類型如果是異常子句中列出的類的基類,它們就不相符)。例如,以下代碼會(huì)按順序打印B,C,D:

class B:
    pass
class C(B):
    pass
class D(C):
    pass

for c in [B, C, D]:
    try:
        raise c()
    except D:
        print "D"
    except C:
        print "C"
    except B:
        print "B"
要注意的是如果異常子句的順序顛倒過(guò)來(lái)(“execpt B”在最前),它就會(huì)打印B,B,B--第一個(gè)匹配的異常被觸發(fā)。

打印一個(gè)異常類的錯(cuò)誤信息時(shí),先打印類名,然后是一個(gè)空格、一個(gè)冒號(hào),然后是用內(nèi)置函數(shù)str()將類轉(zhuǎn)換得到的完整字符串。

  
9.9 迭代器
現(xiàn)在你可能注意到大多數(shù)容器對(duì)象都可以用 for 遍歷:

for element in [1, 2, 3]:
    print element
for element in (1, 2, 3):
    print element
for key in {'one':1, 'two':2}:
    print key
for char in "123":
    print char
for line in open("myfile.txt":
    print line
這種形式的訪問(wèn)清晰、簡(jiǎn)潔、方便。這種迭代器的用法在Python中普遍而且統(tǒng)一。在后臺(tái),for 語(yǔ)句在容器對(duì)象中調(diào)用 iter() 。 該函數(shù)返回一個(gè)定義了 next() 方法的迭代器對(duì)象,它在容器中逐一訪問(wèn)元素。沒(méi)有后續(xù)的元素時(shí),next() 拋出一個(gè) StopIteration 異常通知 for 語(yǔ)句循環(huán)結(jié)束。以下是其工作原理的示例:

>;>;>; s = 'abc'
>;>;>; it = iter(s)
>;>;>; it
<iterator object at 0x00A1DB50>;
>;>;>; it.next()
'a'
>;>;>; it.next()
'b'
>;>;>; it.next()
'c'
>;>;>; it.next()

Traceback (most recent call last):
  File "<pyshell#6>;", line 1, in -toplevel-
    it.next()
StopIteration
了解了迭代器協(xié)議的后臺(tái)機(jī)制,就可以很容易的給自己的類添加迭代器行為。定義一個(gè) __iter__() 方法,使其返回一個(gè)帶有 next() 方法的對(duì)象。如果這個(gè)類已經(jīng)定義了 next(),那么 __iter__() 只需要返回self:

>;>;>; class Reverse:
    "Iterator for looping over a sequence backwards"
    def __init__(self, data):
        self.data = data
        self.index = len(data)
    def __iter__(self):
        return self
    def next(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]

>;>;>; for char in Reverse('spam'):
        print char

m
a
p
s
  
9.10 發(fā)生器
發(fā)生器是創(chuàng)建迭代器的簡(jiǎn)單而強(qiáng)大的工具。它們寫起來(lái)就像是正則函數(shù),需要返回?cái)?shù)據(jù)的時(shí)候使用yield 語(yǔ)句。每次 next() 被調(diào)用時(shí),生成器回復(fù)它脫離的位置(它記憶語(yǔ)句最后一次執(zhí)行的位置和所有的數(shù)據(jù)值)。以下示例演示了發(fā)生器可以很簡(jiǎn)單的創(chuàng)建出來(lái):

>;>;>; def reverse(data):
        for index in range(len(data)-1, -1, -1):
                yield data[index]
               
>;>;>; for char in reverse('golf'):
        print char

f
l
o
g
前一節(jié)中描述了基于類的迭代器,它能作的每一件事發(fā)生器也能作到。因?yàn)樽詣?dòng)創(chuàng)建了 __iter__() 和 next() 方法,發(fā)生器顯得如此簡(jiǎn)潔。

另外一個(gè)關(guān)鍵的功能是兩次調(diào)用之間的局部變量和執(zhí)行情況都自動(dòng)保存了下來(lái)。這樣函數(shù)編寫起來(lái)就比手動(dòng)調(diào)用 self.index 和 self.data 這樣的類變量容易的多。

除了創(chuàng)建和保存程序狀態(tài)的自動(dòng)方法,當(dāng)發(fā)生器終結(jié)時(shí),還會(huì)自動(dòng)拋出 StopIteration異常。綜上所述,這些功能使得編寫一個(gè)正則函數(shù)成為創(chuàng)建迭代器的最簡(jiǎn)單方法。
作者: mq110    時(shí)間: 2005-05-31 16:58
標(biāo)題: Python 指南
10. What Now?
Reading this tutorial has probably reinforced your interest in using Python -- you should be eager to apply Python to solve your real-world problems. Now what should you do?

You should read, or at least page through, the Python Library Reference, which gives complete (though terse) reference material about types, functions, and modules that can save you a lot of time when writing Python programs. The standard Python distribution includes a lot of code in both C and Python; there are modules to read Unix mailboxes, retrieve documents via HTTP, generate random numbers, parse command-line options, write CGI programs, compress data, and a lot more; skimming through the Library Reference will give you an idea of what's available.

The major Python Web site is http://www.python.org/; it contains code, documentation, and pointers to Python-related pages around the Web. This Web site is mirrored in various places around the world, such as Europe, Japan, and Australia; a mirror may be faster than the main site, depending on your geographical location. A more informal site is http://starship.python.net/, which contains a bunch of Python-related personal home pages; many people have downloadable software there. Many more user-created Python modules can be found in a third-party repository at http://www.vex.net/parnassus.

For Python-related questions and problem reports, you can post to the newsgroup comp.lang.python, or send them to the mailing list at python-list@python.org. The newsgroup and mailing list are gatewayed, so messages posted to one will automatically be forwarded to the other. There are around 120 postings a day (with peaks up to several hundred), asking (and answering) questions, suggesting new features, and announcing new modules. Before posting, be sure to check the list of Frequently Asked Questions (also called the FAQ), at http://www.python.org/doc/FAQ.html, or look for it in the Misc/ directory of the Python source distribution. Mailing list archives are available at http://www.python.org/pipermail/. The FAQ answers many of the questions that come up again and again, and may already contain the solution for your problem.
作者: mq110    時(shí)間: 2005-05-31 16:58
標(biāo)題: Python 指南
A. Interactive Input Editing and History Substitution
Some versions of the Python interpreter support editing of the current input line and history substitution, similar to facilities found in the Korn shell and the GNU Bash shell. This is implemented using the GNU Readline library, which supports Emacs-style and vi-style editing. This library has its own documentation which I won't duplicate here; however, the basics are easily explained. The interactive editing and history described here are optionally available in the Unix and CygWin versions of the interpreter.

This chapter does not document the editing facilities of Mark Hammond's PythonWin package or the Tk-based environment, IDLE, distributed with Python. The command line history recall which operates within DOS boxes on NT and some other DOS and Windows flavors is yet another beast.


  
A.1 Line Editing
If supported, input line editing is active whenever the interpreter prints a primary or secondary prompt. The current line can be edited using the conventional Emacs control characters. The most important of these are: C-A (Control-A) moves the cursor to the beginning of the line, C-E to the end, C-B moves it one position to the left, C-F to the right. Backspace erases the character to the left of the cursor, C-D the character to its right. C-K kills (erases) the rest of the line to the right of the cursor, C-Y yanks back the last killed string. C-underscore undoes the last change you made; it can be repeated for cumulative effect.


  
A.2 History Substitution
History substitution works as follows. All non-empty input lines issued are saved in a history buffer, and when a new prompt is given you are positioned on a new line at the bottom of this buffer. C-P moves one line up (back) in the history buffer, C-N moves one down. Any line in the history buffer can be edited; an asterisk appears in front of the prompt to mark a line as modified. Pressing the Return key passes the current line to the interpreter. C-R starts an incremental reverse search; C-S starts a forward search.


  
A.3 Key Bindings
The key bindings and some other parameters of the Readline library can be customized by placing commands in an initialization file called ~/.inputrc. Key bindings have the form


key-name: function-name

or


"string": function-name

and options can be set with


set option-name value

For example:


# I prefer vi-style editing:
set editing-mode vi

# Edit using a single line:
set horizontal-scroll-mode On

# Rebind some keys:
Meta-h: backward-kill-word
"\C-u": universal-argument
"\C-x\C-r": re-read-init-file

Note that the default binding for Tab in Python is to insert a Tab character instead of Readline's default filename completion function. If you insist, you can override this by putting


Tab: complete

in your ~/.inputrc. (Of course, this makes it harder to type indented continuation lines.)

Automatic completion of variable and module names is optionally available. To enable it in the interpreter's interactive mode, add the following to your startup file:A.1  


import rlcompleter, readline
readline.parse_and_bind('tab: complete')

This binds the Tab key to the completion function, so hitting the Tab key twice suggests completions; it looks at Python statement names, the current local variables, and the available module names. For dotted expressions such as string.a, it will evaluate the the expression up to the final "." and then suggest completions from the attributes of the resulting object. Note that this may execute application-defined code if an object with a __getattr__() method is part of the expression.

A more capable startup file might look like this example. Note that this deletes the names it creates once they are no longer needed; this is done since the startup file is executed in the same namespace as the interactive commands, and removing the names avoids creating side effects in the interactive environments. You may find it convenient to keep some of the imported modules, such as os, which turn out to be needed in most sessions with the interpreter.


# Add auto-completion and a stored history file of commands to your Python
# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is
# bound to the Esc key by default (you can change it - see readline docs).
#
# Store the file in ~/.pystartup, and set an environment variable to point
# to it:  "export PYTHONSTARTUP=/max/home/itamar/.pystartup" in bash.
#
# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the
# full path to your home directory.

import atexit
import os
import readline
import rlcompleter

historyPath = os.path.expanduser("~/.pyhistory"

def save_history(historyPath=historyPath):
    import readline
    readline.write_history_file(historyPath)

if os.path.exists(historyPath):
    readline.read_history_file(historyPath)

atexit.register(save_history)
del os, atexit, readline, rlcompleter, save_history, historyPath


  
A.4 Commentary
This facility is an enormous step forward compared to earlier versions of the interpreter; however, some wishes are left: It would be nice if the proper indentation were suggested on continuation lines (the parser knows if an indent token is required next). The completion mechanism might use the interpreter's symbol table. A command to check (or even suggest) matching parentheses, quotes, etc., would also be useful.
作者: mq110    時(shí)間: 2005-05-31 16:59
標(biāo)題: Python 指南
B. Floating Point Arithmetic: Issues and Limitations
Floating-point numbers are represented in computer hardware as base 2 (binary) fractions. For example, the decimal fraction


0.125

has value 1/10 + 2/100 + 5/1000, and in the same way the binary fraction


0.001

has value 0/2 + 0/4 + 1/8. These two fractions have identical values, the only real difference being that the first is written in base 10 fractional notation, and the second in base 2.

Unfortunately, most decimal fractions cannot be represented exactly as binary fractions. A consequence is that, in general, the decimal floating-point numbers you enter are only approximated by the binary floating-point numbers actually stored in the machine.

The problem is easier to understand at first in base 10. Consider the fraction 1/3. You can approximate that as a base 10 fraction:


0.3

or, better,


0.33

or, better,


0.333

and so on. No matter how many digits you're willing to write down, the result will never be exactly 1/3, but will be an increasingly better approximation to 1/3.

In the same way, no matter how many base 2 digits you're willing to use, the decimal value 0.1 cannot be represented exactly as a base 2 fraction. In base 2, 1/10 is the infinitely repeating fraction


0.0001100110011001100110011001100110011001100110011...

Stop at any finite number of bits, and you get an approximation. This is why you see things like:


>;>;>; 0.1
0.10000000000000001

On most machines today, that is what you'll see if you enter 0.1 at a Python prompt. You may not, though, because the number of bits used by the hardware to store floating-point values can vary across machines, and Python only prints a decimal approximation to the true decimal value of the binary approximation stored by the machine. On most machines, if Python were to print the true decimal value of the binary approximation stored for 0.1, it would have to display


>;>;>; 0.1
0.1000000000000000055511151231257827021181583404541015625

instead! The Python prompt (implicitly) uses the builtin repr() function to obtain a string version of everything it displays. For floats, repr(float) rounds the true decimal value to 17 significant digits, giving


0.10000000000000001

repr(float) produces 17 significant digits because it turns out that's enough (on most machines) so that eval(repr(x)) == x exactly for all finite floats x, but rounding to 16 digits is not enough to make that true.

Note that this is in the very nature of binary floating-point: this is not a bug in Python, it is not a bug in your code either, and you'll see the same kind of thing in all languages that support your hardware's floating-point arithmetic (although some languages may not display the difference by default, or in all output modes).

Python's builtin str() function produces only 12 significant digits, and you may wish to use that instead. It's unusual for eval(str(x)) to reproduce x, but the output may be more pleasant to look at:


>;>;>; print str(0.1)
0.1

It's important to realize that this is, in a real sense, an illusion: the value in the machine is not exactly 1/10, you're simply rounding the display of the true machine value.

Other surprises follow from this one. For example, after seeing


>;>;>; 0.1
0.10000000000000001

you may be tempted to use the round() function to chop it back to the single digit you expect. But that makes no difference:


>;>;>; round(0.1, 1)
0.10000000000000001

The problem is that the binary floating-point value stored for "0.1" was already the best possible binary approximation to 1/10, so trying to round it again can't make it better: it was already as good as it gets.

Another consequence is that since 0.1 is not exactly 1/10, adding 0.1 to itself 10 times may not yield exactly 1.0, either:


>;>;>; sum = 0.0
>;>;>; for i in range(10):
...     sum += 0.1
...
>;>;>; sum
0.99999999999999989

Binary floating-point arithmetic holds many surprises like this. The problem with "0.1" is explained in precise detail below, in the "Representation Error" section. See The Perils of Floating Point for a more complete account of other common surprises.

As that says near the end, ``there are no easy answers.'' Still, don't be unduly wary of floating-point! The errors in Python float operations are inherited from the floating-point hardware, and on most machines are on the order of no more than 1 part in 2**53 per operation. That's more than adequate for most tasks, but you do need to keep in mind that it's not decimal arithmetic, and that every float operation can suffer a new rounding error.

While pathological cases do exist, for most casual use of floating-point arithmetic you'll see the result you expect in the end if you simply round the display of your final results to the number of decimal digits you expect. str() usually suffices, and for finer control see the discussion of Pythons's % format operator: the %g, %f and %e format codes supply flexible and easy ways to round float results for display.


  
B.1 Representation Error
This section explains the ``0.1'' example in detail, and shows how you can perform an exact analysis of cases like this yourself. Basic familiarity with binary floating-point representation is assumed.

Representation error refers to that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, C++, Java, Fortran, and many others) often won't display the exact decimal number you expect:


>;>;>; 0.1
0.10000000000000001

Why is that? 1/10 is not exactly representable as a binary fraction. Almost all machines today (November 2000) use IEEE-754 floating point arithmetic, and almost all platforms map Python floats to IEEE-754 "double precision". 754 doubles contain 53 bits of precision, so on input the computer strives to convert 0.1 to the closest fraction it can of the form J/2**N where J is an integer containing exactly 53 bits. Rewriting


1 / 10 ~= J / (2**N)

as


J ~= 2**N / 10

and recalling that J has exactly 53 bits (is >;= 2**52 but < 2**53), the best value for N is 56:


>;>;>; 2L**52
4503599627370496L
>;>;>; 2L**53
9007199254740992L
>;>;>; 2L**56/10
7205759403792793L

That is, 56 is the only value for N that leaves J with exactly 53 bits. The best possible value for J is then that quotient rounded:


>;>;>; q, r = divmod(2L**56, 10)
>;>;>; r
6L

Since the remainder is more than half of 10, the best approximation is obtained by rounding up:


>;>;>; q+1
7205759403792794L

Therefore the best possible approximation to 1/10 in 754 double precision is that over 2**56, or


7205759403792794 / 72057594037927936

Note that since we rounded up, this is actually a little bit larger than 1/10; if we had not rounded up, the quotient would have been a little bit smaller than 1/10. But in no case can it be exactly 1/10!

So the computer never ``sees'' 1/10: what it sees is the exact fraction given above, the best 754 double approximation it can get:


>;>;>; .1 * 2L**56
7205759403792794.0

If we multiply that fraction by 10**30, we can see the (truncated) value of its 30 most significant decimal digits:


>;>;>; 7205759403792794L * 10L**30 / 2L**56
100000000000000005551115123125L

meaning that the exact number stored in the computer is approximately equal to the decimal value 0.100000000000000005551115123125. Rounding that to 17 significant digits gives the 0.10000000000000001 that Python displays (well, will display on any 754-conforming platform that does best-possible input and output conversions in its C library -- yours may not!).
作者: mq110    時(shí)間: 2005-05-31 17:00
標(biāo)題: Python 指南
C. History and License
C.1 History of the software
Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI, see http://www.cwi.nl/) in the Netherlands as a successor of a language called ABC. Guido remains Python's principal author, although it includes many contributions from others.

In 1995, Guido continued his work on Python at the Corporation for National Research Initiatives (CNRI, see http://www.cnri.reston.va.us/) in Reston, Virginia where he released several versions of the software.

In May 2000, Guido and the Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team. In October of the same year, the PythonLabs team moved to Digital Creations (now Zope Corporation; see http://www.zope.com/). In 2001, the Python Software Foundation (PSF, see http://www.python.org/psf/) was formed, a non-profit organization created specifically to own Python-related Intellectual Property. Zope Corporation is a sponsoring member of the PSF.

All Python releases are Open Source (see http://www.opensource.org/ for the Open Source Definition). Historically, most, but not all, Python releases have also been GPL-compatible; the table below summarizes the various releases.

Release  Derived from  Year  Owner  GPL compatible?  
0.9.0 thru 1.2 n/a 1991-1995 CWI yes
1.3 thru 1.5.2 1.2 1995-1999 CNRI yes
1.6 1.5.2 2000 CNRI no
2.0 1.6 2000 BeOpen.com no
1.6.1 1.6 2001 CNRI no
2.1 2.0+1.6.1 2001 PSF no
2.0.1 2.0+1.6.1 2001 PSF yes
2.1.1 2.1+2.0.1 2001 PSF yes
2.2 2.1.1 2001 PSF yes
2.1.2 2.1.1 2002 PSF yes
2.1.3 2.1.2 2002 PSF yes
2.2.1 2.2 2002 PSF yes
2.2.2 2.2.1 2002 PSF yes
2.2.3 2.2.2 2002-2003 PSF yes
2.3 2.2.2 2002-2003 PSF yes


Note: GPL-compatible doesn't mean that we're distributing Python under the GPL. All Python licenses, unlike the GPL, let you distribute a modified version without making your changes open source. The GPL-compatible licenses make it possible to combine Python with other software that is released under the GPL; the others don't.

Thanks to the many outside volunteers who have worked under Guido's direction to make these releases possible.


C.2 Terms and conditions for accessing or otherwise using Python

PSF LICENSE AGREEMENT FOR PYTHON 2.3

This LICENSE AGREEMENT is between the Python Software Foundation (``PSF''), and the Individual or Organization (``Licensee'') accessing and otherwise using Python 2.3 software in source or binary form and its associated documentation.

Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 2.3 alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., ``Copyright &amp; 2001-2003 Python Software Foundation; All Rights Reserved'' are retained in Python 2.3 alone or in any derivative version prepared by Licensee.

In the event Licensee prepares a derivative work that is based on or incorporates Python 2.3 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 2.3.

PSF is making Python 2.3 available to Licensee on an ``AS IS'' basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.

PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

This License Agreement will automatically terminate upon a material breach of its terms and conditions.

Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party.

By copying, installing or otherwise using Python 2.3, Licensee agrees to be bound by the terms and conditions of this License Agreement.

BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0

BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1

This LICENSE AGREEMENT is between BeOpen.com (``BeOpen''), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization (``Licensee'') accessing and otherwise using this software in source or binary form and its associated documentation (``the Software'').

Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee.

BeOpen is making the Software available to Licensee on an ``AS IS'' basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.

BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

This License Agreement will automatically terminate upon a material breach of its terms and conditions.

This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the ``BeOpen Python'' logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page.

By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement.

CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1

This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 (``CNRI''), and the Individual or Organization (``Licensee'') accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation.

Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., ``Copyright &amp; 1995-2001 Corporation for National Research Initiatives; All Rights Reserved'' are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): ``Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013.''

In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1.

CNRI is making Python 1.6.1 available to Licensee on an ``AS IS'' basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.

CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

This License Agreement will automatically terminate upon a material breach of its terms and conditions.

This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party.

By clicking on the ``ACCEPT'' button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement.

ACCEPT

CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
Copyright &amp; 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved.

Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission.

STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
作者: 硬紙卡片    時(shí)間: 2005-06-01 11:34
標(biāo)題: Python 指南
好帖子upup,最好說(shuō)明是那個(gè)版本的?2.3?2.4?
作者: lienjun1973    時(shí)間: 2005-08-13 07:53
標(biāo)題: Python 指南
有沒(méi)有比較精當(dāng)?shù)慕坛?或能下載的單一文件
作者: limodou    時(shí)間: 2005-08-14 19:00
標(biāo)題: Python 指南
不太清楚是重新翻譯還是拷貝,如果是重新翻譯已經(jīng)有人做過(guò)了。如果是拷貝給出下載鏈接更好。

最新的2.4的python教程的翻譯在:

http://wiki.woodpecker.org.cn/moin.cgi/limodou?action=AttachFile&do=get&target=python_2_4_tut.rar
作者: xichen    時(shí)間: 2005-08-14 20:33
標(biāo)題: Python 指南
建議使用python 2.3,因?yàn)?.4在使用中出現(xiàn)一些莫名其妙的問(wèn)題。
作者: Javr    時(shí)間: 2005-08-17 12:48
標(biāo)題: Python 指南
樓主能打個(gè)包么?我第一個(gè)下載
作者: CnOs    時(shí)間: 2005-12-10 05:26
好貼,如果能整理打包下載就更好了
作者: loosir    時(shí)間: 2005-12-25 19:41
強(qiáng)烈要求提供下載!。。。!
作者: LnHScr    時(shí)間: 2005-12-28 08:51
LZ辛苦了~~
作者: codfei    時(shí)間: 2006-09-13 10:16
我才開(kāi)始學(xué)習(xí)   給我的感覺(jué)   介紹這門語(yǔ)言的時(shí)候 都是用簡(jiǎn)單2字來(lái)形容。但是所有的教程都把他和其他的編程語(yǔ)言聯(lián)系起來(lái)。這樣學(xué)習(xí)起來(lái)如果沒(méi)有其他編程語(yǔ)言的基礎(chǔ),很多內(nèi)容是很難理解的……
作者: limodou    時(shí)間: 2006-09-13 11:28
學(xué)多了,自然就要用到許多其它的東西。
作者: 沙灘哥    時(shí)間: 2010-04-09 20:33
有沒(méi)有2.6的翻譯文檔下載
作者: jiaxianhua    時(shí)間: 2010-04-10 13:52

作者: 2gua    時(shí)間: 2010-04-10 16:46
這是比較老的資料了。
作者: johnsilver    時(shí)間: 2015-12-08 16:55
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽




歡迎光臨 Chinaunix (http://72891.cn/) Powered by Discuz! X3.2