先有列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
,要求你把列表裏的每一個值加1,怎麼實現?python
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = [] for i in a:b.append(i+1) a = b print(a)
此方法內存中會同時有兩份列表,所以不適合處理大規模數據。算法
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for index,i in enumerate(a): a[index] +=1 print(a)
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] a = map(lambda x:x+1, a) # <map object at 0x1018da5f8> print(a)
利用map方法根據提供的函數(lambda)對指定序列作映射。express
# 列表生成式:一行代碼完成列表操做 a = [i+1 for i in range(10)]
列表生成式即List Comprehensions,是Python內置的很是簡單卻強大的能夠用來建立list的生成式。數組
# 寫列表生成式時,把要生成的元素x * x放到前面,後面跟for循環,就能夠把list建立出來 >>> [x * x for x in range(1, 11)] [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] # for循環後面還能夠加上if判斷,這樣咱們就能夠篩選出僅偶數的平方 >>> [x * x for x in range(1, 11) if x % 2 == 0] [4, 16, 36, 64, 100] # 用三元運算生成列表 >>> a = range(1,11) >>> a = [i if i < 5 else i*i for i in a] >>> a [1, 2, 3, 4, 25, 36, 49, 64, 81, 100] # 使用兩層循環,能夠生成全排列 >>> [m + n for m in 'ABC' for n in 'XYZ'] ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] # 列表生成式也可使用兩個變量來生成list >>> d = {'x': 'A', 'y': 'B', 'z': 'C' } >>> [k + '=' + v for k, v in d.items()] ['x=A', 'y=B', 'z=C'] # 字符串操做,都變爲小寫 >>> L = ['Hello', 'World', 'IBM', 'Apple'] >>> [s.lower() for s in L] ['hello', 'world', 'ibm', 'apple']
由此能夠看到,經過列表生成式能夠直接建立一個列表。列表建立在內存中,所以列表容量受到內存限制。特別是對一個元素量很大的列表,僅需訪問前幾個元素時,尤爲浪費空間。併發
列表元素能夠按照某種算法推算出來(有規律的數組),則能夠在循環的過程當中不斷推算出後續的元素。這種方式就沒必要建立完整的list,能夠節省大量的空間。app
python中,這種一邊循環一邊計算的機制,稱爲生成器:generator。函數
建立列表生成式和生成器的區別,僅僅是最外層的[]和()。spa
若是要打印出生成器的元素,能夠經過nex()函數獲取generator的下一個返回值。線程
# 生成器保存的是公式,取一次建立一次,只能往前不能後退 >>> a2 = (i for i in range(1000)) >>> a2 <generator object <genexpr> at 0x103761a98> >>> next(a2) 0 >>> next(a2) 1 #生成器走完時,會報錯:StopIteration >>> a3 = (i for i in range(5)) # 限制5個 >>> a3 <generator object <genexpr> at 0x103761e08> >>> next(a3) 0 >>> next(a3) 1 >>> next(a3) 2 >>> next(a3) 3 >>> next(a3) 4 >>> next(a3) Traceback (most recent call last): File "<input>", line 1, in <module> StopIteration
生成器保存的是算法,每次調用next(g)就計算出g的下一個元素的值,直到計算出最後一個元素,沒有更多的元素時,拋出StopIteration的錯誤。code
建立生成器後,不多會調用next(),通常是經過for循環來迭代。
a3 = (i for i in range(5)) for i in a3: # 使用for循環來迭代生成器,不會出現StopIteration報錯,直接結束。 print(i) ''' 0 1 2 3 4 ''' a2 = (i for i in range(3)) while True: # while循環不適用 next(a2) # 報StopIteration錯誤
例如,著名的斐波拉契數列(Fibonacci),除第一個和第二個數外,任意一個數都可由前兩個數相加獲得:1, 1, 2, 3, 5, 8, 13, 21, 34,....
列表生成式寫不出斐波拉契數列,可是函數卻能夠輕鬆打印:
# 用函數來寫生成器,以斐波那契數列爲例 # 重點是賦值語句:a,b = b,a+b def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) # 每次打印b a, b = b, a + b # 0,1——>1,1——>1,2——>2,3 n = n + 1 # n用來計數,每次自加1 return 'done' fib(10)
賦值語句:a, b = b , a + b
至關於:t = (b, a + b) a = t[0] b = t[1] t是一個tuple
fib
函數其實是定義了斐波拉契數列的推算規則,能夠從第一個元素開始,推算出後續任意的元素,這種邏輯其實很是相似generator。
>>> def fib_g(max): ... n, a, b = 0, 0, 1 ... while n < max: ... print('before yield') ... yield b # yield 把函數的執行過程凍結在這一步,而且把b的值返回給外面的next() ... print(b) ... a, b = b, a+b ... n = n + 1 ... return 'done' ... >>> f = fib_g(15) # 將函數轉換爲生成器,有了yeild後,函數名(參數)根本不執行 >>> next(f) before yield 1 >>> next(f) 1 before yield 1 >>> next(f) 1 before yield 2 >>> next(f) 2 before yield 3 >>> next(f) 3 before yield 5
這種生成器和函數類似,但與函數的執行流程不一樣:
函數是順序執行,遇到return語句或最後一行函數語句就返回。
函數轉化爲生成器後,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。
def fib_g(max): n, a, b = 0, 0, 1 while n < max: # print('before yield') yield b # yield 把函數的執行過程凍結在這一步,而且把b的值返回給外面的next() # print(b) a, b = b, a+b n = n + 1 return 'done' # 生成器使用意義:能夠將函數執行中的狀態、數據返回到外部來 data = fib_g(10) print(data) print(data.__next__()) print(data.__next__()) print("乾點別的事") print(data.__next__()) print(data.__next__()) print(data.__next__()) print(data.__next__()) """ <generator object fib_g at 0x1014670f8> 1 1 乾點別的事 2 3 5 8 """
在上例中,循環過程當中不斷調用yield,就會不斷中斷。並且須要設置循環退出條件,不然會產生無限數列。
將函數改寫爲生成器後,一般不會用next()來獲取下一個值,而是使用for循環來迭代。
def fib_g(max): n, a, b = 0, 0, 1 while n < max: yield b # yield 把函數的執行過程凍結在這一步,而且把b的值返回給外面的next() a, b = b, a+b n = n + 1 return 'done' for n in fib_g(6): print(n) """ 1 1 2 3 5 8 """
for循環調用生成器,拿不到生成器的return語句的返回值,要拿到返回值,必須捕獲StopIteration錯誤。
def fib_g(max): n, a, b = 0, 0, 1 while n < max: yield b # yield 把函數的執行過程凍結在這一步,而且把b的值返回給外面的next() a, b = b, a+b n = n + 1 return 'done' g = fib_g(6) while True: try: x = next(g) print('g', x) except StopIteration as e: print('Generator return value:', e.value) break """ g 1 g 1 g 2 g 3 g 5 g 8 Generator return value: done """
send方法做用:
一、喚醒並繼續執行 (next方法只有這個功能)
二、發送一個信息到生成器內部
def range2(n): count = 0 while count < n: print('count', count) count += 1 sign = yield count if sign == 'stop': break print("---sign", sign) return 3333 new_range = range2(3) # 0,1,2 n1 = next(new_range) print(new_range) new_range.send("stop") # 生成器再也不執行後兩步直接終止 """ count 0 <generator object range2 at 0x10244c0f8> Traceback (most recent call last): File "/Users/.../函數生成器2.py", line 20, in <module> new_range.send("stop") StopIteration: 3333 """
以下所示爲生成器與外部交互:
def run(): count = 0 while True: n = yield count print("--", n, count) count += 1 g =run() g.__next__() g.send("alex") g.send("egon") g.send("jack") """ -- alex 0 -- egon 1 -- jack 2 """
#_*_coding:utf-8_*_ __author__ = 'Alex Li' import time def consumer(name): print("%s 準備吃包子啦!" %name) while True: baozi = yield print("包子[%s]來了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') c.__next__() c2.__next__() print("老子開始準備作包子啦!") for i in range(10): time.sleep(1) print("作了2個包子!") c.send(i) c2.send(i) producer("alex") 經過生成器實現協程並行運算
1.列表 列表生成式
2.函數 函數生成器 yield
return返回並停止function
yield返回函數,並凍結當前的執行過程
函數有了yield以後
(1)函數名加()就變成了一個生成器
(2)return在生成器裏,表明生成器的停止,直接報錯
next喚醒凍結的函數執行過程,繼續執行,直到遇到下一個yield
1.喚醒並繼續執行
2.發送一個信息到生成器內部
在Python2中:
range = list
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
xrange = 生成器
>>> a = xrange(10) >>> type(a) <type 'xrange'> >>> for i in a: ... print i ... 0 1 2 3 4 5 6 7 8 9
在Python3中:
range = genetator
>>> range(10) # range(0,10) 生成這個公式沒有正式建立 range(0, 10) >>> type(range(10)) <class 'range'>
xrange :python3中已取消該方法
可直接做用於for循環的數據類型有一下幾種:
1、集合數據類型,如:list、tuple、dict、set、str等;
2、generator,包括生成器表達式(geneator expression)和生成器函數(generator function)兩組構建方式。
上述這些能夠直接做用於for循環的對象統稱爲可迭代對象(Iterable)。可使用isinstance()判斷一個對象是不是Iterable對象。
from collections import Iterable # 可迭代類型 # 使用isinstance()判斷一個對象是不是可迭代對象 isinstance('abc', Iterable) isinstance({}, Iterable) isinstance((x for x in range(10)), Iterable) isinstance(100, Iterable) # 返回False
迭代器定義:能夠被next()函數調用並不斷返回下一個值得對象稱爲迭代器(Iterator)。
生成器是迭代器的一種:
一、生成器都是迭代器對象,但list\dict\str雖然是可迭代對象,但不是迭代器。
二、把list\dict\str等可迭代對象變成迭代器可使用iter()函數
>>> from collections import Iterator >>> isinstance('abc', Iterator) False >>> a = iter('abc') >>> a <str_iterator object at 0x10c584b38> >>> a.__next__() 'a' >>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
list
、dict
、str
等數據類型不是Iterator
? 這是由於Python的Iterator
對象表示的是一個數據流,Iterator對象能夠被next()
函數調用並不斷返回下一個數據,直到沒有數據時拋出StopIteration
錯誤。能夠把這個數據流看作是一個有序序列,但咱們卻不能提早知道序列的長度,只能不斷經過next()
函數實現按需計算下一個數據,因此Iterator
的計算是惰性的,只有在須要返回下一個數據時它纔會計算。
Iterator
甚至能夠表示一個無限大的數據流,例如全體天然數。而使用list是永遠不可能存儲全體天然數的。
凡是可做用於for
循環的對象都是Iterable
類型;
凡是可做用於next()
函數的對象都是Iterator
類型,它們表示一個惰性計算的序列;
集合數據類型如list
、dict
、str
等是Iterable
但不是Iterator
,不過能夠經過iter()
函數得到一個Iterator
對象。
Python的for
循環本質上就是經過不斷調用next()
函數實現的。
for x in [1, 2, 4, 5]: pass # 徹底等價於 # 得到Iterataor對象 it = iter([1, 2, 3, 4, 5]) # 循環 while True: try: # 得到下一個值: x = next(it) except StopIteration: # 遇到StopIteration就退出循環 break