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

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
樓主: mq110
打印 上一主題 下一主題

Python 指南 [復(fù)制鏈接]

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
11 [報(bào)告]
發(fā)表于 2005-05-31 16:54 |只看該作者

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ù)可以通過參數(shù)關(guān)鍵字的形式來調(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')
不過以下幾種調(diào)用是無效的:

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)鍵字都必須來自于形式參數(shù),每個(gè)參數(shù)都有對(duì)應(yīng)的關(guān)鍵字。形式參數(shù)有沒有默認(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ì)介紹),包含了所有沒有出現(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ù)洹T谶@些可變個(gè)數(shù)的參數(shù)之前,可以有零到多個(gè)普通的參數(shù):

def fprintf(file, format, *args):
    file.write(format % args)
  
4.7.4 Lambda 形式
出于適當(dāng)?shù)男枰,有幾種通常在功能性語言和Lisp中出現(xiàn)的功能加入到了Python。通過lambda關(guān)鍵字,可以創(chuàng)建很小的匿名函數(shù)。這里有一個(gè)函數(shù)返回它的兩個(gè)參數(shù)的和:“l(fā)ambda a, b: a+b”。 Lambda 形式可以用于任何需要的函數(shù)對(duì)象。出于語法限制,它們只能有一個(gè)單獨(dú)的表達(dá)式。語義上講,它們只是普通函數(shù)定義中的一個(gè)語法技巧。類似于嵌套函數(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ì)象用途的簡介。簡短起見,不用明確的陳述對(duì)象名或類型,因?yàn)樗鼈兛梢詮膭e的途徑了解到(除非這個(gè)名字碰巧就是描述這個(gè)函數(shù)操作的動(dòng)詞)。這一行應(yīng)該以大寫字母開頭,以句號(hào)結(jié)尾。

如果文檔字符串有多行,第二行應(yīng)該空出來,與接下來的詳細(xì)描述明確分隔。接下來的文檔應(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è)空格)。(這一段譯得不通,有疑問的讀者請(qǐng)參見原文--譯者)

以下是一個(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.

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
12 [報(bào)告]
發(fā)表于 2005-05-31 16:55 |只看該作者

Python 指南

5. 數(shù)據(jù)結(jié)構(gòu)
本章節(jié)深入講述一些你已經(jīng)學(xué)習(xí)過的東西,并且還加入了新的內(nèi)容。

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

append(
x)


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


通過添加指定鏈表的所有元素來擴(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è)元素。如果沒有這樣的元素,就會(huì)返回一個(gè)錯(cuò)誤。
pop(
)


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


返回鏈表中第一個(gè)值為x的元素的索引。如果沒有匹配的元素就會(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è)堆棧來使用,堆棧是這樣的數(shù)據(jù)結(jié)構(gòu),最先進(jìn)入的元素最后一個(gè)被釋放(后進(jìn)先出)。用 append() 方法可以把一個(gè)元素添加到堆棧頂。用不指定索引的 pop() 方法可以把一個(gè)元素從堆棧頂釋放出來。例如:

>;>;>; 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)入的元素釋放出來。例如:

>;>;>; 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ì)于鏈表來講,有三個(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)的元素來調(diào)用函數(shù)(如果某些序列比其它的短,就用None來代替)。如果把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)建鏈表的簡單途徑,無需使用 map(), filter() 以及 lambda。返回鏈表的定義通常要比創(chuàng)建這些鏈表更清晰。每一個(gè)鏈表推導(dǎo)式包括在一個(gè)for語句之后的表達(dá)式,零或多個(gè)for或if語句。返回值是由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 語句
有一個(gè)方法可從鏈表中刪除指定索引的元素:del語句。這個(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)化的語言,也可以加入其它的序列類型,這里有另一種標(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))
如你所見,元組在輸出時(shí)總是有括號(hào)的,以便于正確表達(dá)嵌套結(jié)構(gòu)。在輸入時(shí)可能有或沒有括號(hào)都可以,不過經(jīng)常括號(hào)都是必須的(如果元組是一個(gè)更大的表達(dá)式的一部分)。

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

一個(gè)特殊的問題是構(gòu)造包含零個(gè)或一個(gè)元素的元組:為了適應(yīng)這種情況,語法上有一些額外的改變。一對(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',)
語句 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)。字典在某些語言中可能稱為“聯(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() 方法,或者用切片、或者通過檢索變量來即時(shí)改變。

理解字典的最佳方式是把它看做無序的關(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)鍵字來存儲(chǔ)和析取值。也可以用del來刪除關(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ì)來自一個(gè)模式時(shí),可以用鏈表推導(dǎo)式簡單的表達(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í)解讀出來。

>;>;>; 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語句的條件包括了比較之外的操作符。

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。

比較操作可以通過邏輯操作符and和or組合,比較的結(jié)果可以用not來取反義。這些操作符的優(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為假,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ì)此抱怨,不過它避免了一類在C程序中司空見慣的錯(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

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
13 [報(bào)告]
發(fā)表于 2005-05-31 16:55 |只看該作者

Python 指南

6. 模塊
如果你退出Python解釋器重新進(jìn)入,以前創(chuàng)建的一切定義(變量和函數(shù))就全部丟失了。因此,如果你想寫一些長久保存的程序,最好使用一個(gè)文本編輯器來編寫程序,把保存好的文件輸入解釋器。我們稱之為創(chuàng)建一個(gè)腳本。程序變得更長一些了,你可能為了方便維護(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)前的語義表;,它只是引入了模塊名fibo。你可以通過模塊名按如下方式訪問這個(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ù),通常可以給它賦一個(gè)本地名稱:

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

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

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

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

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

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

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

  
6.1.1 模塊搜索路徑
導(dǎo)入一個(gè)叫spam的模塊時(shí),解釋器先在當(dāng)前目錄中搜索名為spam.py的文件,然后在環(huán)境變量PYTHONPATH指琮的目錄列表中搜索,然后是環(huán)境變量PATH中的路徑列表。如果PYTHONPATH沒有設(shè)置,或者文件沒有找到,接下來搜索安裝目錄,在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)作模塊來加載。這通常會(huì)引發(fā)一個(gè)錯(cuò)誤。請(qǐng)參見 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ū)е聦懭氩怀晒Γ祷氐膕pam.pyc文件就會(huì)視為無效,隨后即被忽略。spam.pyc文件的內(nèi)容是平臺(tái)獨(dú)立的,所以Python模塊目錄可以在不同架構(gòu)的機(jī)器之間共享。

部分高級(jí)技巧:

以-O參數(shù)調(diào)用Python解釋器時(shí),會(huì)生成優(yōu)化代碼并保存在.pyo文件中。通用的優(yōu)化器沒有太多幫助;它只是刪除了斷言(assert)語句。使用-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)該只在確定無誤的場合使用這一選項(xiàng)。

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

通過腳本名在命令行運(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í))而沒有spam.py文件。這樣可以打包發(fā)布比較于逆向工程的Python代碼庫。

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

  
6.2 標(biāo)準(zhǔn)模塊
Python帶有一個(gè)標(biāo)準(zhǔn)模塊庫,并發(fā)布有獨(dú)立的文檔,名為 Python 庫參考手冊(cè) (此后稱其為“庫參考手冊(cè)”)。有一些模塊內(nèi)置于解釋器之中,這些操作的訪問接口不是語言內(nèi)核的一部分,但是已經(jīng)內(nèi)置于解釋器了。這既是為了提高效率,也是為了給系統(tǒng)調(diào)用等操作系統(tǒng)原生訪問提供接口。這類模塊集合是一個(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沒有內(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']
無參數(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”的子模塊。正如同用模塊來保存不同的模塊架構(gòu)可以避免全局變量之間的相互沖突,使用圓點(diǎn)模塊名保存像NunPy或Python Imaging Library之類的不同類庫架構(gòu)可以避免模塊之間的命名沖突。

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

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

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

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

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

from Sound.Effects import echo
這樣就加載了echo子模塊,并且使得它在沒有包前綴的情況下也可以使用,所以它可以如下方式調(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 語句首先核對(duì)是否包中有這個(gè)子項(xiàng),如果沒有,它假定這是一個(gè)模塊,并嘗試加載它。如果沒有找到它,會(huì)引發(fā)一個(gè) ImportError 異常。

相反,使用類似import item.subitem.subsubitem 這樣的語法時(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)上沒有什么方法可以確保一個(gè)叫ECHO.PY的文件應(yīng)該導(dǎo)入為模塊echo、Echo或ECHO。(例如,Windows 95有一個(gè)討厭的習(xí)慣,它會(huì)把所有的文件名都顯示為首字母大寫的風(fēng)格。) DOS 8+3文件名限制又給長文件名模塊帶來了另一個(gè)有趣的問題。

對(duì)于包的作者來說唯一的解決方案就是給提供一個(gè)明確的包索引。import語句按如下條件進(jìn)行轉(zhuǎn)換:執(zhí)行from packae import * 時(shí),如果包中的__init__.py代碼定義了一個(gè)名為__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 * 語句會(huì)從Sound 包中導(dǎo)入以上三個(gè)已命名的子模塊。

如果沒有定義 __all__ ,from Sound.Effects import * 語句不會(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語句從包中明確導(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語句時(shí)它們已經(jīng)定義在Sound.Effects包中了(定義了__all__時(shí)也會(huì)同樣工作)。

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

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

6.4.2 內(nèi)置包(Intra-package)參考
子模塊之間經(jīng)常需要互相引用。例如,surround 模塊可能會(huì)引用echo 模塊。事實(shí)上,這樣的引用如此普遍,以致于import語句會(huì)先搜索包內(nèi)部,然后才是標(biāo)準(zhǔn)模塊搜索路徑。因此surround module 可以簡單的調(diào)用import echo 或者 from echo import echofilter。如果沒有在當(dāng)前的包中發(fā)現(xiàn)要導(dǎo)入的模塊,import語句會(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ò)展包中的模塊集,不過它不常用。

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
14 [報(bào)告]
發(fā)表于 2005-05-31 16:56 |只看該作者

Python 指南

7. 輸入和輸出
有幾種方法可以表現(xiàn)程序的輸出結(jié)果;數(shù)據(jù)可以用可讀的結(jié)構(gòu)打印,也可以寫入文件供以后使用。本章將會(huì)討論幾種可行的做法。

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

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

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

函數(shù)str() 用于將值轉(zhuǎn)化為適于人閱讀的形式,而 repr()轉(zhuǎn)化為供解釋器讀取的形式(如果沒有等價(jià)的語法,則會(huì)發(fā)生SyntaxError 異常) 某對(duì)象沒有適于人閱讀的解釋形式的話,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í)每兩列之間有一個(gè)空格:它總是在參數(shù)之間加一個(gè)空格。)

以上是一個(gè)string.rjust()函數(shù)的演示,這個(gè)函數(shù)把字符串輸出到一列,并通過向左側(cè)填充空格來使其右對(duì)齊。類似的函數(shù)還有 string.ljust() 和 string.center()。這些函數(shù)只是輸出新的字符串,并不改變什么。如果輸出的字符串太長,它們也不會(huì)截?cái)嗨,而是原樣輸出,這會(huì)使你的輸出格式變得混亂,不過總強(qiáng)過另一種選擇(截?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.
如果有超過一個(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ù)念愋,不過如果你沒有定義異常,也不會(huì)有什么從內(nèi)核中主動(dòng)的彈出來。(however, if you don't you get an exception, not a core dump)使用 %s 格式會(huì)更輕松些:如果對(duì)應(yīng)的參數(shù)不是字符串,它會(huì)通過內(nèi)置的 str() 函數(shù)轉(zhuǎn)化為字符串。Python支持用 * 作為一個(gè)隔離(整型的)參數(shù)來傳遞寬度或精度。Python不支持C的 %n 和 %p 操作符。

如果可以逐點(diǎn)引用要格式化的變量名,就可以產(chǎn)生符合真實(shí)長度的格式化字符串,不會(huì)產(chǎn)生間隔。這一效果可以通過使用 form %(name)結(jié)構(gòu)來實(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ì)被如何使用。可選的模式有:‘r',此選項(xiàng)使文件只讀;‘w’,此選項(xiàng)使文件只寫(對(duì)于同名文件,該操作使原有文件被覆蓋); ‘a(chǎn)’,此選項(xiàng)以追加方式打開文件;‘r+’,此選項(xiàng)以讀寫方式打開文件;如果沒有指定,默認(rèn)為‘r’模式。

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

  
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)容,字符串長度為數(shù)值size所指定的大小。如果沒有指定size或者指定為負(fù)數(shù),就會(huì)讀取并返回整個(gè)文件。當(dāng)文件大小為當(dāng)前機(jī)器內(nèi)存兩倍時(shí),就會(huì)產(chǎ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)文件最后一行沒有以換行符結(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ì)量了自文件開頭到指針處的比特?cái)?shù)。需要改變文件對(duì)象指針話話,使用“f.seek(offset, from_what)” 。指針在該操作中從指定的引用位置移動(dòng) offset 比特,引用位置由 from_what 參數(shù)指定。. from_what 值為0表示自文件起初處開始,1表示自當(dāng)前文件指針位置開始,2表示自文件末尾開始。 from_what 可以乎略,其默認(rèn)值為零,此時(shí)從文件頭開始。

>;>;>; 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)閉文件,釋放打開文件后占用的系統(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() 在庫參考手冊(cè)中有文件對(duì)象的完整指南。

  
7.2.2 pickle 模塊
  

我們可以很容易的讀寫文件中的字符串。數(shù)值就要多費(fèi)點(diǎn)兒周折,因?yàn)閞ead() 方法只會(huì)返回字符串,應(yīng)該將其傳入string.atoi()方法中,就可以將'123' 這樣的字符轉(zhuǎn)為相應(yīng)的值。不過,當(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á)為為字符串,這一過程稱之為封裝 (pickling)。從字符串表達(dá)出重新構(gòu)造對(duì)象稱之為拆封(unpickling)。封裝狀態(tài)中的對(duì)象可以存儲(chǔ)在文件或?qū)ο笾,也可以通過網(wǎng)絡(luò)在遠(yuǎn)程的機(jī)器之間傳輸。

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

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

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

pickle 是存儲(chǔ)Python對(duì)象以供其它程序或其本身以后調(diào)用的標(biāo)準(zhǔn)方法。提供這一組技術(shù)的是一個(gè)持久化對(duì)象( persistent object )。因?yàn)?pickle 的用途很廣泛,很多Python擴(kuò)展的作者都非常注意類似矩陣這樣的新數(shù)據(jù)類型是否適合封裝和拆封

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
15 [報(bào)告]
發(fā)表于 2005-05-31 16:57 |只看該作者

Python 指南

8. 錯(cuò)誤和異常
至今為止還沒有進(jìn)一步的談?wù)撨^錯(cuò)誤信息,不過在你已經(jīng)試驗(yàn)過的那些例子中,可能已經(jīng)遇到過一些。Python中(至少)有兩種錯(cuò)誤:語法錯(cuò)誤和異常( syntax errors and exceptions)。

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

>;>;>; 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ò)誤(至少是被檢測到)就發(fā)生在箭頭指向的位置。示例中的錯(cuò)誤表現(xiàn)在關(guān)鍵字print上,因?yàn)樵谒吧倭艘粋(gè)冒號(hào)(:)。同時(shí)也會(huì)顯示文件名和行號(hào),這樣你就可以知道錯(cuò)誤來自哪個(gè)腳本,什么位置。

  
8.2 異常
即使是在語法上完全正確的語句,嘗試執(zhí)行它的時(shí)候,也有可能會(huì)發(fā)生錯(cuò)誤。在程序運(yùn)行中檢測出的錯(cuò)誤稱之為異常,它通常不會(huì)導(dǎo)致致命的問題,你很快就會(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ò)誤信息的一部分顯示出來:示例中的異常分別為零除錯(cuò)誤( ZeroDivisionError ),命名錯(cuò)誤( NameError)和類型錯(cuò)誤( TypeError )。打印錯(cuò)誤信息時(shí),異常的類型作為異常的內(nèi)置名顯示。對(duì)于所有的內(nèi)置異常都是如此,不過用戶自定義異常就不一定了(盡管這是一個(gè)很有用的約定)。標(biāo)準(zhǔn)異常名是內(nèi)置的標(biāo)識(shí)(沒有保留關(guān)鍵字)。

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

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

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

  
8.3 處理異常
通過編程可以處理指定的異常。以下的例子重復(fù)要求用戶輸入一個(gè)值,直到用戶輸入的是一個(gè)合法的整數(shù)為止。不過這個(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 語句按如下方式工作:

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

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

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

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

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

... except (RuntimeError, TypeError, NameError):
...     pass
最后一個(gè)except子句可以省略異常名,把它當(dāng)做一個(gè)通配項(xiàng)使用。一定要慎用這種方法,因?yàn)樗芸赡軙?huì)屏蔽掉真正的程序錯(cuò)誤,使人無法發(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 語句可以帶有一個(gè) else 子句, 該子句只能出現(xiàn)在所有except子句之后。當(dāng)try語句沒有拋出異常時(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 意外的截獲本來不屬于它們保護(hù)的那些代碼拋出的異常。

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

在異常名(列表)之后,也可以為 except 子句指定一個(gè)變量。這個(gè)變量綁定于一個(gè)異常實(shí)例,它存儲(chǔ)在 instance.args 的參數(shù)中。為了方便起見,異常實(shí)例定義了 __getitem__ 和 __str__ ,這樣就可以直接訪問過打印參數(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ì)”)打印出來。

異常處理句柄不止可以處理直接發(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 語句強(qiáng)制拋出異常。例如:

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

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

>;>;>; 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 用戶自定義異常
在程序中可以通過創(chuàng)建新的異常類型來命名自己的異常。異常類通常應(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!'
異常類中可以定義任何其它類中可以定義的東西,但是通常為了保持簡單,只在其中加入幾個(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)參見第 9章,“類”。

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

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

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

在 try 語句中可以使用若干個(gè) except 子句或一個(gè) finally 子句,但兩者不能共存。

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
16 [報(bào)告]
發(fā)表于 2005-05-31 16:57 |只看該作者

Python 指南

9. 類
Python在盡可能不增加新的語法和語義的情況下加入了類機(jī)制。這種機(jī)制是C++和Python's Modula-3的混合。Python中的類沒有在用戶和定義之間建立一個(gè)絕對(duì)的屏障,而是依賴于用戶自覺的不去“破壞定義”。然而,類機(jī)制最重要的功能都完整的保留下來。類繼承機(jī)制允許多繼承,派生類可以覆蓋(override)基類中的任何方法,方法中可以調(diào)用基類中的同名方法。對(duì)象可以包含任意數(shù)量的私有成員。

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

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

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

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

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

我們從一些定義開始。

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

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

屬性可以是只讀過或?qū)懙。后一種情況下,可以對(duì)屬性賦值。你可以這樣作:“modname.the_answer = 42”?蓪懙膶傩砸部梢杂胐el語句刪除。例如:“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í)行的語句,不管它是從腳本文件中讀入還是來自交互式輸入,都是__main__模塊的一部分,所以它們也擁有自己的命名空間。(內(nèi)置命名也同樣被包含在一個(gè)模塊中,它被稱作__builtin__。)

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

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

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

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

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

作用域決定于源程序的文本:一個(gè)定義于某模塊中的函數(shù)的全局作用域是該模塊的命名空間,而不是該函數(shù)的別名被定義或調(diào)用的位置,了解這一點(diǎn)非常重要。另一方面,命名的實(shí)際搜索過程是動(dòng)態(tài)的,在運(yùn)行時(shí)確定的——然而,Python語言也在不斷發(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語句和函數(shù)定將模塊名或函數(shù)綁定于局部作用域。(可以使用global語句將變量引入到全局作用域。)

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

  
9.3.1 類定義語法
最簡單的類定義形式如下:

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

習(xí)慣上,類定義語句的內(nèi)容通常是函數(shù)定義,不過其它語句也可以,有時(shí)會(huì)很有用——后面我們?cè)倩剡^頭來討論。類中的函數(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)語法: 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ì)類屬性賦值,你可以通過給 MyClass.i 賦值來修改它。 __doc__ 也是一個(gè)有效的屬性,返回類的文檔字符串:“A simple example class”。

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

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

這個(gè)實(shí)例化操作(“調(diào)用”一個(gè)類對(duì)象)來創(chuàng)建一個(gè)空的對(duì)象。很多類都傾向于將對(duì)象創(chuàng)建為有初始狀態(tài)的。因此類可能會(huì)定義一個(gè)名為__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ù)通過 __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等等方法。然而,在這里,除非特別說明,我們提到的方法特指類方法)

實(shí)例對(duì)象的有效名稱依賴于它的類。按照定義,類中所有(用戶定義)的函數(shù)對(duì)象對(duì)應(yīng)它的實(shí)例中的方法。所以在我們的例子中,x..f是一個(gè)有效的方法引用,因?yàn)镸yClass.f是一個(gè)函數(shù)。但x.i不是,因?yàn)镸yClass.i是不是函數(shù)。不過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ǔ)起來以后調(diào)用。例如:

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

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

實(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 一些說明
〔有些內(nèi)容可能需要明確一下……〕

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

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

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

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

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

通過 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)然,如果一種語言不支持繼承就,“類”就沒有什么意義。派生類的定義如下所示:

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

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

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

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

派生類中的覆蓋方法可能是想要擴(kuò)充而不是簡單的替代基類中的重名方法。有一個(gè)簡單的方法可以直接調(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>;
這里唯一需要解釋的語義是解析類屬性的規(guī)則。順序是深度優(yōu)先,從左到右。因此,如果在 DerivedClassName (示例中的派生類)中沒有找到某個(gè)屬性,就會(huì)搜索 Base1 ,然后(遞歸的)搜索其基類,如果最終沒有找到,就搜索 Base2,以此類推。

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

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

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

要注意的是傳入exec,eval()或evalfile()的代碼不會(huì)將調(diào)用它們的類視作當(dāng)前類,這與global語句的情況類似,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ò)展的異常體系。

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

raise Class, instance

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

raise instance.__class__, instance
發(fā)生的異常其類型如果是異常子句中列出的類,或者是其派生類,那么它們就是相符的(反過來說--發(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"
要注意的是如果異常子句的順序顛倒過來(“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
這種形式的訪問清晰、簡潔、方便。這種迭代器的用法在Python中普遍而且統(tǒng)一。在后臺(tái),for 語句在容器對(duì)象中調(diào)用 iter() 。 該函數(shù)返回一個(gè)定義了 next() 方法的迭代器對(duì)象,它在容器中逐一訪問元素。沒有后續(xù)的元素時(shí),next() 拋出一個(gè) StopIteration 異常通知 for 語句循環(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)建迭代器的簡單而強(qiáng)大的工具。它們寫起來就像是正則函數(shù),需要返回?cái)?shù)據(jù)的時(shí)候使用yield 語句。每次 next() 被調(diào)用時(shí),生成器回復(fù)它脫離的位置(它記憶語句最后一次執(zhí)行的位置和所有的數(shù)據(jù)值)。以下示例演示了發(fā)生器可以很簡單的創(chuàng)建出來:

>;>;>; 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ā)生器顯得如此簡潔。

另外一個(gè)關(guān)鍵的功能是兩次調(diào)用之間的局部變量和執(zhí)行情況都自動(dòng)保存了下來。這樣函數(shù)編寫起來就比手動(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)建迭代器的最簡單方法。

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
17 [報(bào)告]
發(fā)表于 2005-05-31 16:58 |只看該作者

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.

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
18 [報(bào)告]
發(fā)表于 2005-05-31 16:58 |只看該作者

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.

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
19 [報(bào)告]
發(fā)表于 2005-05-31 16:59 |只看該作者

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!).

論壇徽章:
1
榮譽(yù)版主
日期:2011-11-23 16:44:17
20 [報(bào)告]
發(fā)表于 2005-05-31 17:00 |只看該作者

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.
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP