Python for 循環中 in 關鍵字含義是什麼?

最常用的情況下,我理解,比如

for i in range(1, 5):
print i

這裡用了 in 等同於把 range 返回的 list 裡面的每個元素逐個返回。

我覺得這個內在是不是應該調用了 list 的某個函數做到的?

第二個問題。如果我有一個 file 文件 f,然後也用 for 循環遍歷每一行,應該可以這樣:

for row in f:
print row

那這裡 row 又是什麼類型呢?f 中的每一行作為什麼類型返回呢?感覺問題又回到了是不是應該有一個函數來響應in關鍵字並返回一個對象給前面的變數啊?


關鍵詞:迭代器

簡單來說,for in 語句是一個語法糖,具體是這樣的:

  • 調用一個對象的 __iter__ 方法,方法會返回一個迭代器,所謂迭代器就是實現了 __next__ 方法的對象,如果一個對象本身就實現了 __next__(Python 2 中是直接 「next」 方法,沒有下劃線) ,可以直接返回自身。
  • 調用迭代器的 __next__ 返回迭代器中的「下一個」元素,比如說第一次調用會返回 0,第二次會返回 1,如此這般。
  • 最後沒有元素了,迭代器拋出一個異常來表明自己沒有元素了。for 語句會捕獲這個異常並停下來。

我建議你獨立寫一個斐波那契的迭代器。

Mac 怎麼讓截圖變正常大小啊 QAQ

另外,還有一個銷魂的東西叫做生成器,演示一下如何優雅地斐波那契:

(此後的代碼為了簡潔我都用 Python 3 來寫,用 Python 2 能運行但是性能糟糕。)

def fib(n):
a = 0
b = 1
for _ in range(n):
a, b = b, a+b
yield a

這東西怎麼說呢,能把函數變成一個迭代器,yield 就類似 return,用 next() 來訪問 yield 的返回值,區別是一般的函數 return 完了就完了,但是 yield 返回數據以後,就相當於給函數目前的運行狀態存了檔,下一次調用 next() 的時候函數不會從頭執行,而是會從上次存檔的地方執行,直到再次遇到 yield ,存檔返回數據。

你可以多次調用 next() 求值直到不再 yield 數據,也就是說你調用我的斐波那契函數可以這樣:

for n in fib(10000):
print(n)

# or
sum(fib(10000))
sum(map(lambda x: x*x, fib(42)))


謝邀。剛看到問題以為樓主要問in是什麼意思。

這個for實際上就是迭代,使用的是迭代器(Iterator)。

# 以下代碼在Python 2中運行
for row in f:
print row

# 完全等價於

itr = f.__iter__() # 獲得新的迭代器
while True:
try:
row = itr.next()
except StopIteration:
break
print row

當然了,為了保證Python 2/3的兼容性,上面的代碼應該這樣寫

itr = iter(f)
while True:
try:
row = next(itr)
except StopIteration:
break
print(row)

所有可以迭代的類裡面都會有__iter__方法,用來返回一個迭代器。

迭代器就是一個實現了__next__方法(Python 2里是next方法)的類,每次調用__next__都會返回該容器的下一個值,且迭代器前進1。若已經沒有元素了,就拋出StopIteration異常。

引用:

  1. Python 2中的相關文檔:5. Built-in Types

  2. Python 3中的相關文檔:4. Built-in Types


迭代器。

用dis轉成虛擬機的指令

發現就是GET_ITER, FOR_ITER之類


這都是把range(1:5)和f當成容器來看。文件f既然有行,那row自然是字元串了。


就個人理解:

in 關鍵字實現了一套python中的遍歷協議.

  • 協議A: __iter__ + next

循環時, 程序先使用__iter__ (相當於iter(instance))獲取具有next方法的對象, 然後通過其返回的對象, 不斷調用其next方法, 直到StopIteration錯誤拋出.

class A:
def __iter__(self):
self.limit = 4
self.times = 0
self.init = 1
return self

def next(self):
if self.times &>= self.limit:
raise StopIteration()
else:
x = self.init
self.times += 1
self.init += 1
return x

print "A&>&>&>&>&>&>"
for x in A():
print x

列印結果:

A&>&>&>&>&>&>
1
2
3
4

  • 協議B: __getitem__ + __len__

循環時, 程序先調用__len__ (相當於len(instance))方法獲取長度, 然後循環使用 __getitem__(index) (相當於instance[index])獲取元素, index in range(len(instance))

class B:

def __init__(self):
self._list = [5, 6, 7, 8]

def __getitem__(self, slice):
return self._list[slice]

def __len__(self):
return len(self._list)

print "B&>&>&>&>&>&>"
for x in B():
print x

列印結果:

B&>&>&>&>&>&>
5
6
7
8

  • 協議C: yield關鍵字

def C():
for x in range(9, 13):
yield x

print "C&>&>&>&>&>&>"
for x in C():
print x

列印結果:

C&>&>&>&>&>&>
9
10
11
12

從上邊可以看出, ABC三種方式都可以實現in的循環, 對於A和B, 如果一個類把這兩個方案都實現了怎麼辦?

class D(A, B):
pass
print "D&>&>&>&>&>&>"
for x in D():
print x

列印結果:

D&>&>&>&>&>&>
1
2
3
4

可見, in優先使用的是A計劃.

仍在學習python中, 錯誤之處還請指點


我剛學python,看了樓上大神們的回答感覺還是有點懵逼,我來說下我怎麼理解的,如果錯了,望大神糾正

in的意思是遍歷目錄里的數據


&>&>&> i = ["1","2"]
&>&>&> for j in i:
print(j)
...
1
2
等價於:
&>&>&> i = ("fuck","up")
&>&>&> j = 0
&>&>&> while j &< len(i): print(i[j]) j = j+1 ... fuck up


推薦閱讀:

如何學習遞歸呢?
有沒有程序或代碼可以直接破壞計算機的硬體?
typedef void(*Fun) (void)是什麼意思?
C++的語言設計有哪些缺陷?
如何入門Python3?

TAG:編程語言 | Python | 編程 | Python3x | Python使用技巧 |