第十四章 迭代和推導

2021-10-02 10:12:43 字數 4244 閱讀 9523

我們以及知道for迴圈可以用於python中任何序列型別,包括列表、元組以及字串,如下所示:

>>

>

for i in[1

,2,3

,4]:

...print

(i)...

1234

>>

>

>>

>

for i in(1

,2,3

,4):

...print

(i)...

1234

>>

>

>>

>

for i in

'spam':.

..print

(i)...

spam

實際上for迴圈可用於任何可迭代物件;

可迭代物件是python語言中比較新的概念,但是它在語言設計中普遍存在。本質上,這就是序列觀念的一種通用化:如果物件是實際儲存的序列或事可以在迭代工具上下文中一次產生乙個結果的物件,那麼就看作是可迭代的。總之,可迭代物件包括實際序列,以及能夠按照需求計算的虛擬序列;

所有帶有__next__方法的物件會前進到下乙個結果,而當達到一系列結果的末尾時,__next__方法會引發stopiteration異常,這種物件在python中被稱為迭代器。任何這類物件也能以for迴圈或其他迭代工具遍歷,因為所有迭代工具內部工作起來都是在每次迭代中呼叫__next__方法,並通過捕捉stopiteration異常來確定何時離開。

為了簡化手動**,python還提供了內建函式next,它會自動呼叫乙個物件的__next__方法。即給定乙個迭代器物件x,呼叫next(x)等同於x.next(),但是next(x)更簡單且可移植新更好。

另有一點需要注意。for迴圈在開始時,會首先把可迭代物件傳入內建函式iter,

for迴圈在開始時,會首先把可迭代物件傳入內建函式iter,並由此拿到乙個迭代器;而iter呼叫返回的迭代器物件有著所需的next方法。iter函式與next和__next__很像,在它的內部呼叫了__iter__方法。

該協議基於分別用在不同的兩個步驟中的物件:

在實際**中,我們可以通過模擬for迴圈內部呼叫的例子,來學習迭代協議中的第一步的具體工作方式:

>>

> l =[1

,2,3

]>>

>

type

(l)<

class

'list'

>

>>

> i =

iter

(l)>>

>

type

(i)<

class

'list_iterator'

>

>>

>

>>

> i.__next__()1

>>

> i.__next__()2

>>

> i.__next__()3

>>

> i.__next__(

)traceback (most recent call last)

: file ""

, line 1,in

stopiteration

最初的一步對於檔案來說不是必需的,因為檔案物件自身就是迭代器。由於檔案只支援一次迭代,檔案有自己的__next__方法,因此不需要像這樣返回乙個不同的物件;

儘管python迭代工具會自動呼叫這些函式,我們也可以使用它們來手動地應用迭代協議。如以的互動式命令列內容展示了自動和手動迭代之間的等價性:

>>

> l =[1

,2,3

]>>

>

>>

>

for i in l:..

.print

(i, end=

' ')..

.123

>>

>

>>

>

>>

>

>>

> i =

iter

(l)>>

>

while

true:.

..try:..

. x =

next

(i)...

except stopiteration:..

.break..

.print

(x, end=

' ')..

.123

>>

>

除了檔案以及像列表這樣的物理的序列外,其他型別也有其適用的迭代器。例如字典鍵的經典方法是顯式地獲取它的鍵列表:

>>

> d =

>>

>

for key in d.keys():

...print

(key, d[key]).

.. a 1b 2

c 3

其實在python中,字典作為乙個可迭代物件自帶的乙個迭代器,在迭代上下文中,會自動一次返回乙個鍵:

>>

> i =

iter

(d)>>

>

next

(i)'a'

>>

>

next

(i)'b'

>>

>

next

(i)'c'

>>

>

next

(i)traceback (most recent call last)

: file ""

, line 1,in

stopiteration

最終效果是,我們不再需要呼叫keys方法來遍歷字典鍵——for迴圈將使用迭代協議在每次迭代的時候獲取乙個鍵:

>>

>

for key in d:..

.print

(key, d[key]).

.. a 1b 2

c 3

我們已經了解了迭代協議的工作方式,與for迴圈一起使用的列表推導,是主要的迭代協議上下文之一;

有一種需求,當我們需要對列表中的每乙個元素都增加10,可以用以下**實現:

>>

> l =[1

,2,3

,4,5

]>>

>

for i in

range

(len

(l)):.

.. l[i]

+=10..

.>>

> l[11

,12,13

,14,15

]

上述**雖然可以實現需求,但是並不是python中優化的『最佳實踐』。我們可以使用列表推導來代替該迴圈:

>>

> l =[1

,2,3

,4,5

]>>

> l =

[x +

10for x in l]

>>

> l[11

,12,13

,14,15

]

最終的結果是一致的,但列表推導需要更少的**,並且執行速度會大大提公升。

為了從語法上了解它,我們繼續看列表推導的語句:

l =

[x +

10for i in l]

列表推導寫在乙個方括號中,因為它們是最終構建乙個新的列表的一種方式。它們以我們所組合成的乙個任意的表示式開始,在這裡我們使用乙個迴圈變數組合得到表示式。

作為乙個特別有用的擴充套件,推導表示式中巢狀的for迴圈可以有乙個關聯的if分句,來過濾掉那些測試不為真的結果項。

>>

> l =[1

,2,3

,4,5

,6]>>

>

>>

> l =

[i for i in l if i <4]

>>

> l[1

,2,3

]

如果需要的話,列表推導甚至可以變得更加複雜——例如,我們可以通過編寫一系列for分句,讓推導包含巢狀的迴圈。實際上,它們的完整語法允許任意數量的for分句,並且每乙個for分句都可以帶有乙個可選的關聯的if分句。

第十四章約束

約束 constraint 是一種保證資料完整性的規則。約束設定在單個字段或者多個字段組合上,寫入這些欄位的行資料必須要符合約束的規則 約束的五種型別 not null 非空約束,指定某列的所有行資料不能包含空值 unique 唯一性約束,指定列或者列的組合的所有行資料必須唯一 primary ke...

第十四章 約束

第十四章 約束 練習1 1.學校有乙個選課系統,其中包括如下關係模式 系 系編號 主鍵,系名稱 唯一鍵,系主任 非空約束,系所在校去 取值範圍只能在南湖校區和渾南校區 create table xi xi no varchar2 10 primary key,xi name varchar2 10 ...

第十四章 集合

1.集合 把個數不定的物件一起帶著走 集合是乙個存放任意數量的引用的物件的容器 多個物件放在另乙個物件中,此物件可成為乙個集合物件 注意 如果集合物件建立時不指定泛型,則在當前集合中可以存放任意型別的物件 包括 collection list set map list 介面的實現類有arraylis...