循環可以有一個 else 子句;它在循環迭代完整個列表(對於 for )或執行條件 為 false (對於 while )時執行,但循環被 break 中止的情況下不會執行。
以下搜索素數的示例程序演示了這個子句
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'
默認值在函數 定義 作用域被解析,如下所示 i = 5
def f(arg=i): print arg i = 6 f() will print 5.
引入一個形如 **name 的參數時,它接收一個字典(參見 typesmapping ) ,該字典包含了所有未出現 在形式參數列表中的關鍵字參數。
這里可能還會組合使用一個形如 *name (下一小節詳細介紹) 的形 式 參數,它接收一個元組(下一節中會詳細介紹),包含了所有沒有出現在形式 參數列表中的參數值。
( *name 必須在 **name 之前出現) 例如,我們這樣定 義一個函數
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]
It could be called like this: 它可以像這樣調用
cheeseshop("Limburger", "It's very runny, sir.", "It's really very, VERY runny, sir.", shopkeeper='Michael Palin', client="John Cleese", sketch="Cheese Shop Sketch")
and of course it would print: 當然它會按如下內容打印 -- 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
出於實際需要,有幾種通常在函數式編程語言例如 Lisp 中出現的功能加入到了 Python 。
通過 lambda 關鍵字,可以創建短小的匿名函數。這里有一個函數返 回它的兩個參數的和: lambda a, b: a+b 。
Lambda 形式可以用於任何需要的 函數對象。出於語法限制,它們只能有一個單獨的表達式。
語義上講,它 們只是 普通函數定義中的一個語法技巧。類似於嵌套函數定義,lambda 形式可以從外部作用域引用變量。
>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42
>>> f(1) 43
你也可以把鏈表當做隊列使用,隊列作為特定的數據結構,最先進入的元素最先 釋放(先進先出)。不 過,列表這樣用效率不高。
相對來說從列表末尾添加和彈 出很快;在頭部插入和彈出很慢(因為,為了一 個元素,要移動整個列表中的所 有元素)。
要實現隊列,使用 collections.deque ,它為在首尾兩端快速插入和 刪除而設計。例如
>>> from collections import deque >>> queue = deque(["Eric", "John", "Michael"]) >>> queue.append("Terry") # Terry arrives
>>> queue.append("Graham") # Graham arrives
>>> queue.popleft() # The first to arrive now leaves
'Eric'
>>> queue.popleft() # The second to arrive now leaves
'John'
>>> queue # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])
filter(function, sequence) 返回一個sequence(序列),包括了給定序列中所有調用 function(item) 后返回值為true的元素。(如果可能的話, 會返回相同的類型)。
如果該序列(sequence) 是一個 string (字符串)或者 tuple (元組),返回值必定是同一類型,否則,它 總是 list 。
>>> 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) 為每一個元素依次調用 function(item) 並將返回值 組成一個鏈表返回。例 如,以下程序計算立方
>>> def cube(x): return x*x*x ... >>> map(cube, range(1, 11)) [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
可以傳入多個序列,函數也必須要有對應數量的參數,執行時會依次用各序列上 對應的元素來調用函數 (如果某些序列比其它的短,就用 None 來代替)。
如果把 None做為一個函數傳入,則直接返回參數做為替代。例如
>>> seq = range(8) >>> def add(x, y): return x+y ... >>> map(add, seq, seq) [0, 2, 4, 6, 8, 10, 12, 14]
reduce(func, sequence) 返回一個單值,它是這樣構造的:首先以序列的 前兩個元素調用函數 function ,再以返回值和第三個參數調用,依次執行下去。
例如,以 下程序計算 1 到 10 的整數之和
>>> def add(x,y): return x+y ... >>> reduce(add, range(1, 11)) 55
acquire參數為false不阻塞:
List Comprehensions 列表推導式
列表推導式比 map() 更復雜,可使用復雜的表達式和嵌套函數
>>> 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[i]*vec2[i] for i in range(len(vec1))] [8, 12, -54]
Looping Techniques 循環技巧
在字典中循環時,關鍵字和對應的值可以使用 iteritems() 方法同時解讀出來 >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} >>> for k, v in knights.iteritems(): ... print k, v ... gallahad the pure robin the brave When looping through a sequence, the position index and corresponding value can be retrieved at the same time using the enumerate() function. : 在序列中循環時,索引位置和對應值可以使用 enumerate() 函數同時得 到。 >>> for i, v in enumerate(['tic', 'tac', 'toe']): ... print i, v ... 0 tic 1 tac 2 toe To loop over two or more sequences at the same time, the entries can be paired with the zip() function. : 同時循環兩個或更多的序列,可以使用 zip() 整體打包。 >>> questions = ['name', 'quest', 'favorite color'] >>> answers = ['lancelot', 'the holy grail', 'blue'] >>> for q, a in zip(questions, answers): ... print 'What is your {0}? It is {1}.'.format(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. To loop over a sequence in reverse, first specify the sequence in a forward direction and then call the reversed() function. : 需要逆向循環序列的話,先正向定位序列,然后調用 reversed() 函數 >>> for i in reversed(xrange(1,10,2)): ... print i ... 9
7
5
3
1 To loop over a sequence in sorted order, use the sorted() function which returns a new sorted list while leaving the source unaltered. 要按排序后的順序循環序列的話,使用 sorted() 函數,它不改動原序列,而是 生成一個新的已排序的序 列。
``Compiled'' Python files “編譯的” Python 文件
對於引用了大量標准模塊的短程序,有一個提高啟動速度的重要方法,如果在 spam.py 所在的目錄下存 在一個名為 spam.pyc 的文件,它會 被視為 spam 模塊的預“編譯”(``byte-compiled'' ,二進制編 譯) 版本。
用於創建 spam.pyc 的這一版 spam.py 的修改時間記 錄在 spam.pyc 文件中,如果兩者不匹 配,.pyc 文件就被忽略。
通常你不需要為創建 spam.pyc 文件做任何工作。一旦 spam.py 成功編譯,就 會嘗試生成對應版本的 spam.pyc 。
以 -O 參數調用Python解釋器時,會生成優化代碼並保存在 .pyo 文件中。現 在的優化器沒有太多 幫助;它只是刪除了斷言( assert )語句。
使用 -O 參 參數, 所有 的字節碼( bytecode )都 會被優化; .pyc 文 件被忽略, .py 文件被編譯為優化代碼。
來自 .pyc 文件或 .pyo 文件中的程序不會比來自 .py 文件的運行更快; .pyc 或 .pyo 文件只是在它們加載的時候更快一些。
dir()函數 列出了所有類型的名稱:變量,模塊,函數,等等。
dir() 不會列出內置函數和變量名。如果你想列出這些內容,它們在標准模塊 builtin 中定義
Packages 包
對於包的作者來說唯一的解決方案就是給提供一個明確的包索引。 import 語句按如下條件進行轉換: 執行 from package import * 時,如果包中的 __init__ .py 代碼定義了一個名為__all__的列表,就 會按照列表中給出的模塊名進行導入。
新版本的包發布時作者可以任 意更新這個列表。如果包作者不想 import * 的時候導入他們的包中所有模塊, 那么也可能會決定不支持它(import *)。例如, Sounds/ Effects/ init .py 這個文件可能包括如下代碼
__all__ = ["echo", "surround", "reverse"]
這意味着 from Sound.Effects import * 語句會從 sound 包中導入以上三個已命名的子模塊。
有兩種方式可以寫平方和立方表 >>> for x in range(1, 11): ... print repr(x).rjust(2), repr(x*x).rjust(3), ... # Note trailing comma on previous line ... print repr(x*x*x).rjust(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 '{0:2d} {1:3d} {2:4d}'.format(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
還有另一個方法, zfill() 它用於向數值的字符串表達左側填充 0。該 函數可以正確理解正負號 >>> '12'.zfill(5) '00012'
>>> '-3.14'.zfill(7) '-003.14'
>>> '3.14159265359'.zfill(5) '3.14159265359'
類
__doc__ 也是一個有效的屬性,返回類的文檔字符串。
客戶應該小心使用數據屬性--客戶可能會因為隨意修改數據屬性而破壞了本來由方法維護的數據一致性。需要注意的是,客戶只要注意避免命名沖突,就可以 隨意向實例中添加數據屬性而不會影響方法的有效性 .
Python 有兩個用於繼承的函數:
函數 isinstance() 用於檢查實例類型: isinstance(obj, int) 只有在 obj.__class__ 是 int 或其它從 int 繼承 的類型.
函數 issubclass() 用於檢查類繼承: issubclass(bool, int) 為 True ,因為 bool 是 int 的子類。但是, issubclass(unicode, str) 是 False ,因為 unicode 不 是 str 的子類(它們只是共享一個通用祖先類 basestring )。
super用來執行父類中的函數:
class Foo(object): def hi(self): print 'hi,Foo'
class Foo2(Foo): def hi(self): super(Foo2, self).hi() if __name__ == '__main__': foo2 = Foo2() foo2.hi() 運行結果: hi,Foo
注意,Foo類必須繼承某個類(並且這個繼承鏈開始於object類),否則會報錯。
只能從對像內部訪問的“私有”實例變量,在 Python 中不存在。然而,也有 一個變通的訪問用於大多數 Python 代碼:以一個下划線開頭的命名(例如_spam )會被處理為 API 的非公開部分(無論它是一個函數、方法或數據 成員)。它會被視為一個實現細節,無需公開。
有時類似於Pascal中“記錄(record)”或C中“結構(struct)”的數據類型 很有用,它將一組已命名的 數據項綁定在一起。一個空的類定義可以很好的實現:
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
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
在后台, for 語句在容器 對象中調用 iter() 。 該函數返回一個定義了 next() 方法的迭代器對象,它在容器中逐一訪問元素。 沒 有后續的元素時, next() 拋出一個 StopIteration 異常通知 for 語句循環結束。
>>> 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 "", line 1, in ? it.next() StopIteration
了解了迭代器協議的后台機制,就可以很容易的給自己的類添加迭代器行為。定 義一個 iter () 方法, 使其返回一個帶有 next() 方法的對象。如果這個類 已經定義了 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
Generators 生成器:
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