命名空間
名稱空間是存放變量名和賦值綁定關(guān)系的地方
名稱空間共 3 種:
- locals: 是函數(shù)內(nèi)的名稱空間,包括局部變量和形參
- globals: 全局變量外盯,函數(shù)定義所在模塊的名稱空間
- builtins: 內(nèi)置模塊的名稱空間
不同變量的作用域不同是由這個變量所在的命名空間決定的
作用域范圍:
- 全局變量:全局有效摘盆,全局存活
- 局部變量:局部有效,局部存活
查看作用域的方法:globals(), locals()
作用域的查找規(guī)則:LEGB
閉包
閉包:返回的函數(shù)對象饱苟,不僅僅是一個函數(shù)對象孩擂,在該函數(shù)外還包裹了一層作用域,這使得箱熬,該函數(shù)無論在何處調(diào)用类垦,優(yōu)先使用自己外層的作用域
def func():
name = 'jack'
def inner():
print('函數(shù)變量:', name)
return inner
f = func()
f()
# 返回結(jié)果: 函數(shù)變量:jack
生成器
列表生成式
# 將列表中的每一個值都進(jìn)行自乘
# 可以通過列表生成式來完成
>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a = [i*i for i in a]
>>> a
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 以上就是通過簡單的列表生成式來實現(xiàn)的
生成器:
通過列表生成式,可以直接創(chuàng)建一個列表城须,但是受到內(nèi)存限制蚤认,列表的容量是有限的。
列表元素通過某種算法糕伐,再循環(huán)中不斷推算出后續(xù)的元素砰琢,這種一邊循環(huán)一邊計算的機(jī)制,稱為生成器:generator
# 要創(chuàng)建一個 generator 很簡單良瞧,就是將列表生成式中的 [] 改成 ()
>>> l = [i*i for i in range(10)]
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x*x for x in range(10))
>>> g
<generator object <genexpr> at 0x7f77ffd6cdb0>
# 創(chuàng)建 l 和 g 的區(qū)別就是最外層的[] 和 (), l 是一個list陪汽,而 g 是 generator,可以直接打印獲取 list 所有元素褥蚯,但 generator 需要通過 next() 一個一個獲取
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# 直到最后獲取不到拋出 StopIteration 錯誤
# 但用上面 next(g) 獲取太麻煩掩缓,可以通過 for 循環(huán)
>>> g = (x*x for x in range(10))
>>> for n in g:
... print(n)
...
0
1
4
9
16
25
36
49
64
81
# 而且這樣也不會報錯
著名的斐波拉契數(shù)列(Fibonacci),除第一個和第二個數(shù)外遵岩,任意一個數(shù)可由前兩個數(shù)相加所得
斐波拉契數(shù)列通過列表生成式無法寫出來你辣,但是可以通過函數(shù)打印出來
def fin(max):
n, a, b = 0, 0, 1
while n < max:
print b
a, b = b, a+b
n += 1
return 'done'
data = fin(5)
print(data)
# 執(zhí)行結(jié)果為
1
1
2
3
5
# 上面 fin 函數(shù)實際上是定義了斐波拉契數(shù)列的推算規(guī)則,可以從第一個元素推算出后續(xù)任意的元素
# 要講上面函數(shù)變成 generator尘执,只需要把 print b 改為 yield b
def fin(max):
n, a, b = 0, 0, 1
while n < max:
# print b
yield b
a, b = b, a+b
n += 1
return 'done'
data = fin(5)
print(data)
# 執(zhí)行結(jié)果:<generator object fib at 0x00000232F05DEF68>
# 這是函數(shù)中定義 generator 的一種方法舍哄,如果一個函數(shù)內(nèi)包含 yield 字段,那么這個函數(shù)就不再是一個普通函數(shù)誊锭,而是一個 generator
# generator執(zhí)行過程和函數(shù)是不同的表悬,函數(shù)執(zhí)行是順序執(zhí)行,需要 return語句或者最后一行語句返回丧靡,而 generator函數(shù)蟆沫,則是每次調(diào)用 next() 的時候執(zhí)行籽暇,遇到 yield語句返回,如沒有next()饭庞,函數(shù)執(zhí)行到 yield 是就停止不再繼續(xù)執(zhí)行了戒悠,再次被 next() 調(diào)用時從上次返回的 yield 語句繼續(xù)執(zhí)行下,在次遇到 yield 語句返回并停止
迭代器
- 可迭代對象
可以直接作用于 for 循環(huán)的對象稱為可迭代對象:Iterable
可直接作用于 for 循環(huán)的數(shù)據(jù)類型有以下幾類:
一類是集合數(shù)據(jù)類型:list ,tuple, dict, set, str 等
一類是 generator舟山,包括生成器和帶 yield 的generator functions
可以使用 isinstance() 判斷一個對象是否是 Iterable(可迭代)對象
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance((), Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance(123, Iterable) # 整數(shù)就不是可迭代對象
False
而生成器不但可以作用于 for 循環(huán)绸狐,還可以被 next() 函數(shù)不斷的調(diào)用并返回下一個值,直到最后拋出 Stoplteration 錯誤并返回
- 迭代器
可以被 next() 函數(shù)調(diào)用并不斷返回下一個值的對象稱為 迭代器:Iterator
可以用 isinstance()判斷一個對象是否是 Iterator(迭代)對象:
>>> isinstance((i for i in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance('abc', Iterator)
False
# 生成器都是 Iterator(迭代器)對象累盗,但 list寒矿,str, dict 雖然是 Iterable(可迭代對象), 但不是 Iterator(迭代器)
可以通過 iter() 函數(shù)把 Iterable 變成 Iterator
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
Python 中 Iterator
對象表示的是一個數(shù)據(jù)流,Iterator
對象可以被 next() 函數(shù)調(diào)用并不斷返回下一個數(shù)據(jù)若债,直到?jīng)]有數(shù)據(jù)拋出 StopIteration
錯誤符相,可以把這個數(shù)據(jù)流看做是一個有序序列,但我們卻不能提前知道序列的長度蠢琳,只能不斷通過next()
函數(shù)實現(xiàn)按需計算下一個數(shù)據(jù)主巍,所以Iterator
的計算是惰性的,只有在需要返回下一個數(shù)據(jù)時它才會計算挪凑。
- 總結(jié)
凡是可作用于 for 循環(huán)的對象都是 Iterable 類型
凡是可作用于 next() 函數(shù)的對象都是 Iterator 類型孕索,它們表示一個惰性計算的序列
集合類型如 list,dict躏碳,str等都是 Iterable搞旭,但不是 Iterator, 但是可以通過 iter() 函數(shù)獲得一個 Iterator 對象
python3 的 for 循環(huán)本質(zhì)上就是通過不斷調(diào)用 next() 函數(shù)實現(xiàn)的