一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python for循環中的陷阱詳解

Python for循環中的陷阱詳解

2021-03-17 00:09hoxis Python

這篇文章主要給大家介紹了關于Python for循環中陷阱的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

前言

Python 中的 for 循環和其他語言中的 for 循環工作方式是不一樣的,今天就帶你深入了解 Python 的 for 循環,看看它是如何工作的,以及它為什么按照這種方式工作。

循環中的陷阱

我們先來看一下 Python 循環中的「陷阱」,在我們了解了循環的工作方式后,再來看下這些陷阱到底是怎么出現的。

陷阱 1:循環兩次

現在我們先假設有一個數字組成的列表,和一個用于返回這些數字的平方的生成器:

?
1
2
>>> nums = [1, 2, 3, 4]
>>> squares = (n**2 for n in nums)

我們可以將這個生成器對象傳遞給元組構造器,從而可以得到一個元組:

?
1
2
>>> tuple(squares)
(1, 4, 9, 16)

這個時候,如果我們再將這個構造器對象傳遞給 sum 函數,按理說應該會返回這些數字的和吧:

?
1
2
>>> sum(squares)
0

返回的是個 0,先拖住下巴。

陷阱 2:檢查是否包含

我們還是使用上面的數字列表和生成器:

?
1
2
>>> nums = [1, 2, 3, 4]
>>> squares = (n**2 for n in nums)

如果我 squares 生成器中是否包含 9,答案是肯定的,若果我再問一次呢?

Python for循環中的陷阱詳解

你敢答應嗎

?
1
2
3
4
>>> 9 in squares
True
>>> 9 in squares
False

發現,第二次不靈了~

怎么不靈了

陷阱 3:拆包

現在假設有一個字典:

?
1
>>> counts = {1:'a', 2:'b'}

然后,我們用多個變量對字典進行拆包:

?
1
>>> x,y = counts

你覺得這時候,x 和 y 中會是什么?

?
1
2
3
4
>>> x
1
>>> y
2

我們只得到了鍵。

下面,我們先來了解下 Python 中的循環工作原理,然后再反過頭來看這些陷阱問題。

一些概念

首先,先了解一些基本概念:

可迭代和序列

可迭代就是指任意可以使用 for 循環遍歷的東西,可迭代意味著可以遍歷,任何可以遍歷的東西都是可迭代的。

?
1
2
for item in some_iterable:
 print(item)

序列是一種常見的可迭代類型,如列表、元組、字符串等。

序列是可迭代的,它有著一些特點,它們是從 0 開始索引,索引長度不超過序列的長度;它們有序列長度;并且它們可以被切分。

Python 中的大部分東西都是可以迭代的,但是可以迭代并不意味著它是序列。如集合、字典、文件和生成器都是可迭代的,但是它們都不是序列。

?
1
2
3
4
>>> my_set = {1, 2, 3}
>>> my_dict = {'k1': 'v1', 'k2': 'v2'}
>>> my_file = open('some_file.txt')
>>> squares = (n**2 for n in my_set)

總結下來就是,任何可以用 for 循環遍歷的東西都是可迭代的,序列可迭代的類型中的一種,Python 還有著許多其他種類的可迭代類型。

迭代器

迭代器就是可以驅動可迭代對象的東西。你可以從任何可迭代對象中獲得迭代器,你也可以使用迭代器來手動對它的迭代進行遍歷。

下面有三個可迭代對象:一個集合、一個元祖和一個字符串:

?
1
2
3
>>> nums = {1,2,3,4}
>>> coors = (4,5,6)
>>> words = "hello hoxis"

我們可以使用 Python 的內置函數 iter ,從這些可迭代對象中獲取到迭代器:

?
1
2
3
4
5
6
>>> iter(nums)
<setiterator object at 0x7fa8c194ad70>
>>> iter(coors)
<tupleiterator object at 0x7fa8c1959610>
>>> iter(words)
<iterator object at 0x7fa8c19595d0>

一旦我們有了迭代器,我們就可以使用其內置函數  next() 來獲取它的下一個值:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> nums = {1,2,3,4}
>>> num_iter = iter(nums)
>>> next(num_iter)
1
>>> next(num_iter)
2
>>> next(num_iter)
3
>>> next(num_iter)
4
>>> next(num_iter)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

若果迭代到頭了,也就是沒有下一個值了,就會拋出 StopIteration 異常。也就是說,它不會繼續循環取獲取第一個值。

是不是有點懵逼了?

  • 可迭代對象是可以迭代的東西
  • 迭代對象器實際上是遍歷可迭代對象的代理
  • 迭代器沒有長度,它們不能被索引。
  • 可以使用迭代器來做的唯一有用的事情是將其傳遞給內置的 next 函數,或者對其進行循環遍歷
  • 可以使用 list() 函數將迭代器轉換為列表
?
1
2
3
4
5
6
7
8
>>> nums = {1,2,3,4}
>>> num_iter = iter(nums)
>>> next(num_iter)
1
>>> list(num_iter)
[2, 3, 4]
>>> list(num_iter)
[]

若果想再次將其轉換為列表,明顯地,得到的是一個空列表。

其實這也是迭代器的一個重要特性:惰性,只能使用一次,只能循環遍歷一次。并且,在我們調用 next() 函數之前,它不會做任何事情。因此,我們可以創建無限長的迭代器,而創建無限長的列表則不行,那樣會耗盡你的內存!

可迭代對象不一定是迭代器,但是迭代器一定是可迭代的:

 

對象 可迭代? 迭代器?
可迭代對象 不一定
迭代器
生成器
列表 ×

 

其實,Python 中有許多迭代器,生成器是迭代器,Python 的許多內置類型也是迭代器。例如,Python 的 enumerate 和 reversed 對象就是迭代器。zip, map 和 filter 也是迭代器;文件對象也是迭代器。

Python 中的 for 循環

其實,Python 并沒有傳統的 for 循環,什么是傳統的 for 循環?

我們看下 Java 中的 for 循環:

?
1
2
3
4
5
int[] integers = {1234};
for (int j = 0; j<integers.length; j++) {
 int i = integers[j];
 System.out.println(i);
}

這是一種 C風格 的 for 循環,JavaScript、C、C++、Java、PHP 和一大堆其他編程語言都有這種風格的 for 循環,但是 Python 確實沒有。

Python 中的我們稱之為 for 循環的東西,確切的說應該是 foreach 循環:

?
1
2
3
numbers = [1, 2, 3, 5, 7]
for n in numbers:
 print(n)

和 C風格 的 for 循環不同之處在于,Python 的 for 循環沒有索引變量,沒有索引變量的初始化,邊界檢查和索引變量的增長。

這就是 Python 的 for 循環的不同之處!

使用索引?

你可能會懷疑,Python 的 for 循環是否在底層使用了索引,下面我們手動的使用 while 循環和索引來遍歷:

?
1
2
3
4
5
6
7
8
9
10
>>> nums = [1,2,3,4]
>>> i = 0
>>> while i < len(nums):
...  print(num[i])
...  i += 1
...
0
1
2
3

對于列表,這樣遍歷是可以的,但不代表適用于所有可迭代對象,它只適用于序列。

比如,我們對一個 set 使用這種方法遍歷,會得到一個異常:

?
1
2
3
4
5
6
7
8
9
>>> set = {1,2,3}
>>> i = 0
>>> while i < len(set):
...  print(set[i])
...  i += 1
...
Traceback (most recent call last):
 File "<stdin>", line 2, in <module>
TypeError: 'set' object does not support indexing

因為 set 不是序列,因此不支持索引遍歷。

我們不能使用索引手動對 Python 中的每一個迭代對象進行遍歷。對于那些不是序列的迭代器來說,更是行不通的。

實現沒有 for 的循環

從上文可以看出,Python 中的 for 循環不使用索引,它使用的是迭代器。讓我們來看下它是如何工作的。

通過上文,我們了解到了迭代器和 iter、next 函數,現在我們可以嘗試不用 for 循環來遍歷一個可迭代對象。

下面是一個正常的 for 循環:

?
1
2
3
def funky_for_loop(iterable, action_to_do):
 for item in iterable:
  action_to_do(item)

我們要嘗試用迭代器的方法和 while 實現上面 for 循環的邏輯,大致步驟如下:

  • 獲取給定可迭代對象的迭代器;
  • 調用迭代器的 next() 方法獲取下一項;
  • 對當前項數據進行處理;
  • 如果捕獲到 StopIteration ,那么就停止循環
?
1
2
3
4
5
6
7
8
9
def funky_for_loop(iterable, action_to_do):
 iterator = iter(iterable)
 while not done_looping:
  try:
   item = next(iterator)
  except StopIteration:
   break
  else:
   action_to_do(item)

Python 底層的循環工作方式基本上如上代碼,就是迭代器驅動的 for 循環。

再次回到循環陷阱

陷阱 1:耗盡的迭代器

陷阱 1 中,因為生成器是迭代器,迭代器是惰性的,也是一次性的,在已經遍歷過一次的情況下,再對其求和,返回的就是一個 0。

陷阱 2:部分消耗迭代器

陷阱 2 中,我們兩次詢問 9 是否存在于同一個生成器中,得到了不同的答案。

這是因為,第一次詢問時,Python 已經對這個生成器進行了遍歷,也就是調用 next() 函數查找 9,找到后就會返回 True,第二次再詢問 9 是否存在時,會從上次的位置繼續 next() 查找。

?
1
2
3
4
5
6
7
>>> nums = [1,2,3,4,5]
>>> squares = (n**2 for n in nums)
>>> 9 in squares
True
# 此時打印出來
>>> list(squares)
[16, 25]

陷阱 3:拆包是迭代

當直接在字典上迭代時,得到的是鍵:

?
1
2
3
4
5
6
>>> counts = {1:'a',2:'b'}
>>> for i in counts:
...  print(i)
...
1
2

而對字典拆包時,和在字典上遍歷是一樣的,都是依賴于迭代器協議,因此得到的也是鍵。

總結

序列是迭代器,但是不是所有的迭代器都是序列。迭代器不可以被循環遍歷兩次、不能訪問其長度,也不能使用索引。

迭代器是 Python 中最基本的可迭代形式。如果你想在代碼中做一個惰性迭代,請考慮迭代器,并考慮使用生成器函數或生成器表達式。

最后,請記住,Python 中的每一種迭代都依賴于迭代器協議,因此理解迭代器協議是理解 Python 中的循環的關鍵。

原文鏈接:https://opensource.com/article/18/3/loop-better-deeper-look-iteration-python

好了以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.jianshu.com/p/6f66aeeb0093

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本网络视频www色高清免费 | 人人艹在线视频 | 国产在线观看网站 | 女人全身裸露无遮挡免费观看 | 69罗莉视频在线观看 | 精品国产自在现线拍400部 | 高清欧美videossexo免费 | 欧美艳星kagneyiynn高清 | 午夜小视频免费观看 | 俺去俺来也在线www色官网 | 国产精品久久久天天影视香蕉 | 亚洲欧洲网站 | 精品国语国产在线对白 | 欧美日韩高清一区 | 无码专区aaaaaa免费视频 | 色综合中文字幕在线亚洲 | 青青草原网 | 嫩草视频在线观看免费 | 农村妇女野外牲交一级毛片 | 亚洲精品国产在线观看 | 国产aⅴ一区二区三区 | 国产精品一级片 | 娇小XXXXX第一次出血 | 99综合视频 | 亚洲国产欧美另类va在线观看 | 成人福利在线视频免费观看 | 欧美男同video | 亚洲 欧美 制服 校园 动漫 | 国产一级一级一级成人毛片 | 好看的亚洲视频 | 国产东北3p真实在线456视频 | 日韩综合网 | 午夜福利体检 | 岛国不卡 | 亚洲国产精品久久精品成人网站 | 爽新片xxxxxxx | 免费国产一级观看完整版 | 精品一区二区三区免费观看 | 久久国产精品高清一区二区三区 | 无码乱人伦一区二区亚洲一 | 男人j进女屁股视频在线观看 |