文章目錄
-
-
- 1. 生成器
-
- 1.1 生成器表達式 (...)
- 1.2 生成器函數 yield
- 1.3 調用生成器 next() / send()
- 2. 疊代器
-
- 2.1 可疊代對象 - 可以for循環
-
- 1.可用 `isinstance( .., Iterable)` 判斷可疊代對象
- 2.疊代器還能被 `next()` 函數調用
- 2.2 疊代器 - 可被 next() 調用
-
- 1.可用 `isinstance(... , Iterator)` 判斷
- 2.可以通過 `iter(Iterable)` 建立疊代器
- 3.python的`for`循環本質
- 4.range()不是疊代器,xrange()是
- 2.3 生成器是一種特殊的疊代器
- 3. 裝飾器
-
- 3.1 實作需求!!!!!
- 3.2 相關知識
-
- 1. 函數是一個對象
- 2. 高階函數(函數作為參數/傳回值)
- 3. 嵌套函數
- 4. 閉包(延伸了作用域的函數)
- 5. 關于閉包的變量(nonlocal)
- 3.3 裝飾器
-
- 1. 裝飾器:高階函數 + 嵌套函數 + 閉包
- 2. 文法糖 @
- 3. 進階裝飾器 - 有參
- 4. 一些讨論
-
1. 生成器
squares = [i**2 for i in range(10000)]
for i in squares:
pass
把所有元素都存在清單裡,占用了大量記憶體,而實際上每次隻用到清單中的一個元素。
生成器:
1.惰性計算
2.邊執行邊計算,無需一次性存入大量資料
3.實際上一直在執行next(操作),直到無值可取
1.1 生成器表達式 (…)
圓括号
squares = (i**2 for i in range(100000))
for i in squares:
pass
【例】求0-500的和
sum((i for i in range(501)))
## 5050
1.2 生成器函數 yield
【例】 生成斐波那契數列
1.數組疊代和存儲
2.若有中間操作,每次隻用到其中一個元素,比如每次隻列印一個數字(不需要一次性使用全部元素),可以把這個中間操作放在循環裡面執行
3.這種情況也可以構造生成器函數,友善單獨進行中間操作,把print換成yield即可
當我們調用這個函數fib(),它首先會順序執行,當執行到yield時停止,yield就會傳回yield後面跟着的那個元素,相當于 return 的功能,所不同的是,執行完傳回之後仍然會停在這裡,直到我們執行下一次的操作 next(),繼續執行剩餘操作,并傳回到while判斷語句,符合條件則執行 yield,再次傳回,并停留在這裡,等待下一次操作 next()…
總結:在每次調用 next() 的時候執行,遇到 yield 語句則傳回(相應元素),再次執行時從上次傳回的 yield 語句處繼續執行
1.3 調用生成器 next() / send()
[作業系統] 多任務 - 協程
2. 疊代器
2.1 可疊代對象 - 可以for循環
可直接作用于for循環的對象,統稱為可疊代對象:
Iterable
- 清單,元組,字典,集合,字元串,檔案
- 生成器
1.可用 isinstance( .., Iterable)
判斷可疊代對象
isinstance( .., Iterable)
from collections import Iterable
isinstance([1,2,3], Iterable)
# True
isinstance("python", Iterable)
# True
2.疊代器還能被 next()
函數調用
next()
比如生成器不僅可用于
for
循環,還可以被
next()
函數調用,直到沒有資料可取,抛出
StopIteration
(生成器不僅是可疊代對象,還是疊代器)
squares = (i**2 for i in range(5))
isinstance(squares, Iterable)
# True
print(next(squares))
print(next(squares))
print(next(squares))
0
1
4
2.2 疊代器 - 可被 next() 調用
可以被
next()
函數調用,并且不斷傳回下一個值,直到沒有資料可取的對象(可耗盡),稱為疊代器
Iterator
- 生成器 是 Iterable 也是 Iterator
- 清單,元組,字典,集合,字元串 是 Iterable 不是 Iterator
- 檔案 是 Iterable 也是 Iterator
- zip, enumerate 等 itertools 裡的函數是 Iterator
- range() 不是 Iterator
1.可用 isinstance(... , Iterator)
判斷
isinstance(... , Iterator)
from collections import Iterator
squares = (i**2 for i in range(5)) ## 生成器
isinstance(squares, Iterator)
# true
with open("test.txt", "r", encoding = "utf-8") as f:
print(isinstance(f, Iterator)) ## 檔案
# True
isinstance([1,2], Iterator) ## 清單
# False
isinstance("python", Iterator) ## 字元串
# False
isinstance(range(5), Iterator) ## range函數
# False
x = [1, 2]
y = ["a", "b"]
for i in zip(x, y): ## zip函數
print(i)
# (1, 'a')
# (2, 'b')
isinstance(zip(x, y), Iterator)
# True
num = [1, 2, 3]
for i in enumerate(num): # enumerate函數
print(i)
# (0, 1)
# (1, 2)
# (2, 3)
isinatance(enumerate(num), Iterator)
# True
2.可以通過 iter(Iterable)
建立疊代器
iter(Iterable)
清單,元組,字典,集合,字元串 是 Iterable 不是 Iterator,但可以用 iter 建立 Iterator
isinstance(iter([1,2,3]), Iterator)
# True
PS:Iterator表示的是一個資料流,不斷被next()調用并傳回下一個資料直到StopIteration異常。但,我們不能提前知道序列長度,隻能通過 next() 按需計算下一個資料,(惰性計算),而清單等類型可以計算序列長度。Iterator甚至可以表示一個無限大的資料流,但清單等顯然不可能做到。
3.python的 for
循環本質
for
結合上一條,
for item in Iterable
實際上先通過
iter(Iterable )
函數建立可疊代對象的疊代器
Iterator
,然後對疊代器不斷調用
next()
方法來擷取下一個值,并将其指派給
item
,當遇到
StopIteration
的異常後 結束循環。
4.range()不是疊代器,xrange()是
nums = range(10)
isinstance(nums, Iterator)
# False
next(nums)
# TypeError # 不可被next()調用
【python 2】
輸入 range(100) 則傳回一個清單 [0, 1, 2, … ,99],如果輸入 range(100000…000) 那麼首先需要占用大量的記憶體空間來存儲這個清單結果,并且在清單的生成過程中就卡死了
輸入 xrange(100) 則傳回一個對象(疊代器),占用極小的記憶體空間,存儲的不是清單結果,而是生成清單的方式
【python 3 】已經把 range 改為了 xrange
2.3 生成器是一種特殊的疊代器
疊代:通路集合元素的一種方式(在原來的基礎上,得到新的元素)
疊代器:一個對象,可以用很小的記憶體資源來通路集合元素(通過調用 next() 方法,疊代擷取資料),比如 for temp in Iterable , [ xxx for xxx in iterable] 存儲的不是清單結果,而是生成清單的方式。
生成器:一個函數,傳回的是疊代器,能夠記錄目前疊代到的狀态,并配合 next() 函數進行疊代,可以生成資料。
特殊在于,疊代器必須是一個類裡有 iter 方法和 next() 方法,它的對象才能是一個疊代器,但是生成器不需要,隻要一個函數裡有 yield,那麼這個函數就是生成器,可以通過 next() 函數來調用這個生成器,進而生成資料,每調用一次隻生成一個值,然後暫停執行,直到下次調用。
[作業系統] 多任務 - 協程
3. 裝飾器
3.1 實作需求!!!!!
【1】需要對已開發上線的程式添加某些功能
【2】不能對程式中函數的源代碼進行修改
【3】不能改變程式中函數的調用方式
裝飾器,就是對原函數進行【裝飾】
3.2 相關知識
1. 函數是一個對象
可以将函數指派給變量,調用變量就是調用函數
def square(x):
return x**2
print(type(square)) # square 是 function 類的一個執行個體
# <class 'function'>
pow_2 = square # 相當于給square函數起了别名
print(pow_2(5))
print(square(5))
# 25
# 25
2. 高階函數(函數作為參數/傳回值)
接收函數作為參數,或者傳回函數作為傳回值,滿足之一稱為高階函數
def square(x):
return x**2
def pow_2(fun):
return fun
f = pow_2(square) ### Not pow_2(square(8))
f(8)
# 64
3. 嵌套函數
在函數内部又定義一個函數
def outer():
print("outer is running")
def inner():
print("inner is running")
inner()
outer()
# outer is running
# inner is running
4. 閉包(延伸了作用域的函數)
閉包是延伸了作用域的函數
閉包 = 函數+外層環境的變量
如果一個函數定義在另一個函數的作用域内,并且引用了外層函數的變量,則該函數稱為閉包
5. 關于閉包的變量(nonlocal)
一旦在内層函數重新定義了相同名字的變量,則該變量成為局部變量,外層函數對其的定義和初始化全部失效(例子裡就是 x = x +100 的 x 變成局部變量了,無初始值,報錯)
可以使用
nonlocal
允許内層函數修改閉包變量,且不會變成内部變量
global
的作用對象是全局變量(聲明代碼塊中的變量使用外部全局的同名變量),
nonlocal
的作用對象是外層變量(使用在閉包中的,聲明内層函數使用外層的同名變量)
3.3 裝飾器
1. 裝飾器:高階函數 + 嵌套函數 + 閉包
個人了解:
裝飾器函數是個【嵌套函數】,新增的功能由内層函數實作。
裝飾器函數也是個【高階函數】,外層函數把原函數作為參數傳入(内層函數執行時用到),外層函數的傳回值是内層函數,注意傳回值是 inner,不是 inner()
裝飾器的内層函數是個【閉包】,執行時用到了外層的參數(原函數)
2. 文法糖 @
3. 進階裝飾器 - 有參
【函數有參】可以在裝飾器的内層函數引入參數(保險起見,兩種參數都寫上),把外層函數的參數傳遞給内層函數
def timer(func):
def inner(*args, **kwargs):
...
func(*args, **kwargs)
...
@timer
def f1(n):
...
f1(2)
【函數有傳回值】可以在裝飾器的内層函數調用 原函數 的時候,将結果賦給一個變量比如 res,将 res 作為記憶體函數的傳回值
【裝飾器有參】裝飾器本身需要一些參數,比如針對不同的函數進行裝飾,比如針對不同的需求進行裝飾,需要傳遞一些選擇分支性質的參數
4. 一些讨論
- 原函數的屬性被掩蓋了,傳回的是裝飾器函數的内層函數:f1 = timer(f1),是以 f1 = inner
- 可以使用 @wraps 實作回歸本源