您好,登錄后才能下訂單哦!
現在有個需求,看列表[0, 1, 2, 3, 4, 5],要求你把列表里的每個值加1,你怎么實現?
可以使用for循環,while循環
map方式
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = map(lambda x:x+1, a)
>>> a
<map object at 0x101d2c630>
>>> for i in a:print(i)
...
3
5
7
9
11
高級方式:
列表生成式方式
>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a = [i for i in range(10)]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
通過列表生成式,我們可以直接創建一個列表。但是,收到內存限制,列表容量是有限的。而且,創建一個包含100萬個元素的列表,不僅占用很大的存儲空間,如果我們僅僅使用其中的幾個元素,那后面的元素所占用的空間就浪費掉了。
所以,如果列表中的元素可以按照某種算法推算出來,那是否可以在循環的過程中推算出后續的元素呢?就不需要創建完整的list,從而節省大量的空間。在Python中,一邊循環一邊計算的機制,稱為生成器:generator.
要創建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的[]改成(),就創建了一個generator
生成器的特性:
1.預先定義一個生產輸的范圍,使用一個生產一個,不占用內存空間
2.只能往下不斷取數,不能回退
3.走到最后,報stopIteration錯誤
##這里生成大量的數據,需要一段時間
>>> a = [i for i in range(100000000000000)]
##列表生成式,立刻生成,因為是調用net()方法時才產生數據,調用一次產生一次
>>> a = (i for i in range(100000000000000))
>>>
>>>
>>> a = [i for i in range(10)]
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> g = (i*2 for i in range(10))
>>> g
<generator object <genexpr> at 0x00000237FF9BF2B0>
通過next()函數獲得generator的下一個返回值
>>> next(g)
0
>>> next(g)
2
>>> next(g)
4
>>>
>>> next(g)
16
>>> next(g)
18
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
#可使用for循環調用
#創建了一個generator后,基本上永遠不會調用next(),而是通過for循環來迭代它,并且不需要關心StopIteration的錯誤
>>> g = (i*2 for i in range(10))
>>> for n in g:
... print(n)
...
0
2
4
6
8
10
12
14
16
18
>>>
generator非常強大。如果推算的算法比較復雜,用類似列表生成式的for循環無法實現的時候,可以使用函數來實現
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
# 相當于t = a+b, a = b,b = t,但不需要顯式寫出臨時變量t就可以賦值
a, b = b, a + b
n = n + 1
return 'done'
fib(10)
E:\PythonProject\python-test\venvP3\Scripts\python.exe E:/PythonProject/python-test/BasicGrammer/test.py
1
1
2
3
5
8
13
21
34
55
Process finished with exit code 0
仔細觀察。fib函數實際上已經定義了斐波那契數列的推算規則,可以從第一個元素開始推算出后續的任意元素,這種邏輯其實已經很類似generator,實際只需要把print(b)改為yield b就變成了生成器。
如果一個函數定義中包含yield關鍵字,那么這個函數就不再是一個普通函數,而是一個generator.
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
# 用for循環輸出內容
for i in fib(10):
print(i)
E:\PythonProject\python-test\venvP3\Scripts\python.exe E:/PythonProject/python-test/BasicGrammer/test.py
1
1
2
3
5
8
13
21
34
55
Process finished with exit code 0
print(fib(10))
<generator object fib at 0x000002BF85F8B888>
普通函數是順序執行的,遇到return語句或最后一行函數語句就返回數據,并凍結當前的執行過程
generator的執行流程是每次調用next()的時候執行,遇到yeild語句返回,再次調用next()時從上次yeild語句處繼續執行。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
data = fib(10)
print(data.__next__())
print(data.__next__())
print("做別的事情")
print(data.__next__())
print(data.__next__())
print(data.__next__())
E:\PythonProject\python-test\venvP3\Scripts\python.exe E:/PythonProject/python-test/BasicGrammer/test.py
1
1
做別的事情
2
3
5
Process finished with exit code 0
用for循環調用generator時,發現拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
g = fib(10)
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
E:\PythonProject\python-test\venvP3\Scripts\python.exe E:/PythonProject/python-test/BasicGrammer/test.py
g: 1
g: 1
g: 2
g: 3
g: 5
g: 8
g: 13
g: 21
g: 34
g: 55
Generator return value: done
Process finished with exit code 0
send作用
1.喚醒并繼續執行
2.發送一個信息到生成器內部
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: vita
def fib(max):
n,a,b = 0,0,1
while n < max:
#print(b)
sign=yield b
a,b = b,a+b
if sign=="stop":
print(sign)
n += 1
return 'done'
f = fib(6)
print(next(f))
print(next(f))
print(next(f))
f.send("stop")
print(next(f))
E:\PythonProject\python-test\venvP3\Scripts\python.exe E:/PythonProject/python-test/BasicGrammer/test.py
1
1
2
stop
5
python3中
range()就是創建了一個生成器,用到的時候才會生成數據
Python2中
range()是創建一個定義大小的列表,
xrange()是創建了一個一個生成器,和Python3中的range()相同
>python3
Python 3.6.2 (v3.6.2:5fd33b5, Jul 8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> range(100000000000000000000)
range(0, 100000000000000000000)
>>> type(range(10))
<class 'range'>
>>> quit()
>python2
Python 2.7.16 (v2.7.16:413a49145e, Mar 4 2019, 01:37:19) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> xrange(100000000)
xrange(100000000)
>>> range(10000000)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37...]
>>> type(range(10))
<type 'list'>
>>> type(xrange(10))
<type 'xrange'>
我們已經知道,可以用于for循環的數據類型有以下幾種:
一類是集合數據類型,如list,tuple,dict,set,str等;
一類是generator,包括生成器和帶yeild的generator function。
這些可以直接作用于for循環的對象稱為可迭代對象(Iterable)
可以使用isinstance()判斷一個對象是否是Iterable對象
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
生成器不但可以用for循環,還可以被next()函數不斷調用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續返回下一個值。
可以被next()函數調用并不斷返回下一個值的對象稱為迭代器(Iterator)
可以使用isinstance()判斷一個對象是否是Iterator對象
python3
>>> from collections import Iterator
>>> isinstance(range(10),Iterator)
False
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是迭代器,但list,tuple,set,dict,str雖然是可迭代對象,但不是迭代器。
可以使用iter()函數把list,str,dict,set變為迭代器
>>> isinstance(iter([]),Iterator)
True
>>> isinstance(iter(""),Iterator)
True
>>> isinstance(iter({}),Iterator)
True
>>>
為什么list,set,dict,str不是迭代器?
因為Python的迭代器對象表示的是一個數據流,Iterator對象可以被next()函數調用并不斷返回下一個數據,直到沒有數據時拋出StopIteration錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過next()函數實現按需計算下一個數據,所以Iterator的計算是惰性的,只有在需要返回下一個數據時才會計算。
Iterator甚至可以表示一個無限大的數據流,例如全體自然數。而使用list是永遠不可能存儲全體自然數的。
1.凡是可作用于for循環的對象都是Iterable類型;
2.凡是可作用于next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;
3.集合數據類型如list、dict、str等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。
4.Python3的for循環本質上就是通過不斷調用next()函數實現的,例如:
for x in [1, 2, 3, 4, 5]:
pass
實際上完全等價于:
# 首先獲得Iterator對象:
it = iter([1, 2, 3, 4, 5])
# 循環:
while True:
try:
# 獲得下一個值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循環
break
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。