python全棧開發- 前⽅⾼能-迭代器 python_day_12
今日主要內容 1, 函式名的應用,第一類物件 函式名可以像變數一樣進行使用 1.賦值 2.作為list元素 3.作為引數 4.作為返回值
2, 閉包 內部函式訪問外部函式的區域性變數. 好處:
- 1.安全
- 2.常駐記憶體. 提高效率
- 3, 迭代器
可迭代物件(Iterable):內部包含__iter__(). 迭代器(Iterator): 內部含有__iter__() __next__() str, list, tuple, set, dict f, range
迭代器的特點:
- 1.省記憶體
- 2.惰性機制
- 3.只能向前.
11. 前方高能-迭代器 本節主要內容:
- 1. 函式名的使⽤以及第⼀類物件
- 2. 閉包
- 3. 迭代器
⼀. 函式名的運⽤.
函式名是⼀個變數, 但它是⼀個特殊的變數, 與括號配合可以執⾏函式的變數.
1. 函式名的記憶體地址
def func():
print("呵呵")
print(func)
結果:
<function func at 0x1101e4ea0>
2. 函式名可以賦值給其他變數
def func():
print("呵呵")
print(func)
a = func # 把函式當成⼀個變數賦值給另⼀個變數
a() # 函式調⽤ func()
3. 函式名可以當做容器類的元素
def func1(): print("呵呵") def func2(): print("呵呵") def func3(): print("呵呵") def func4(): print("呵呵") lst = [func1, func2, func3] for i in lst: i()
4. 函式名可以當做函式的引數
def func():
print("吃了麼")
def func2(fn):
print("我是func2")
fn() # 執⾏傳遞過來的fn
print("我是func2")
func2(func) # 把函式func當成引數傳遞給func2的引數fn.
5. 函式名可以作為函式的返回值
def func_1(): print("這⾥是函式1") def func_2(): print("這⾥是函式2") print("這⾥是函式1") return func_2 fn = func_1() # 執⾏函式1. 函式1返回的是函式2, 這時fn指向的就是上⾯函式2 fn() # 執⾏上⾯返回的函式
⼆. 閉包 什麼是閉包? 閉包就是內層函式, 對外層函式(非全域性)的變數的引⽤. 叫閉包
def func1():
name = "alex"
def func2():
print(name) # 閉包
func2()
func1()
結果:
alex
我們可以使⽤__closure__來檢測函式是否是閉包. 使⽤函式名.__closure__返回cell就是 閉包. 返回None就不是閉包
def func1():
name = "alex"
def func2():
print(name) # 閉包
func2()
print(func2.__closure__) # (<cell at 0x10c2e20a8: str object at
0x10c3fc650>,)
func1()
問題, 如何在函式外邊調⽤內部函式呢?
def outer():
name = "alex"
# 內部函式
def inner():
print(name)
return inner
fn = outer() # 訪問外部函式, 獲取到內部函式的函式地址
fn() # 訪問內部函式
那如果多層巢狀呢? 很簡單, 只需要⼀層⼀層的往外層返回就⾏了
def func1():
def func2():
def func3():
print("嘿嘿")
return func3
return func2
func1()()()
由它我們可以引出閉包的好處. 由於我們在外界可以訪問內部函式. 那這個時候內部函 數訪問的時間和時機就不⼀定了, 因為在外部, 我可以選擇在任意的時間去訪問內部函式. 這 個時候. 想⼀想. 我們之前說過, 如果⼀個函式執⾏完畢. 則這個函式中的變數以及區域性命名 空間中的內容都將會被銷燬. 在閉包中. 如果變數被銷燬了. 那內部函式將不能正常執⾏. 所 以. python規定. 如果你在內部函式中訪問了外層函式中的變數. 那麼這個變數將不會消亡. 將會常駐在記憶體中. 也就是說. 使⽤閉包, 可以保證外層函式中的變數在記憶體中常駐. 這樣做 有什麼好處呢? 非常⼤的好處. 我們來看⼀個關於爬⾍的程式碼:
from urllib.request import urlopen
def but():
content = urlopen("http://www.xiaohua100.cn/index.html").read()
def get_content():
return content
return get_content
fn = but() # 這個時候就開始載入校花100的內容
# 後⾯需要⽤到這⾥⾯的內容就不需要在執⾏⾮常耗時的⽹絡連線操作了
content = fn() # 獲取內容
print(content)
content2 = fn() # 重新獲取內容
print(content2)
綜上, 閉包的作⽤就是讓⼀個變數能夠常駐記憶體. 供後⾯的程式使⽤.
三. 迭代器 我們之前⼀直在⽤可迭代物件進⾏迭代操作. 那麼到底什麼是可迭代物件. 本⼩節主要討 論可迭代物件. ⾸先我們先回顧⼀下⽬前我們所熟知的可迭代物件有哪些: str, list, tuple, dict, set.
我們發現這⼏個可以進⾏for迴圈的東⻄都有__iter__函式, 包括range也有. 可以⾃⼰試⼀ 下. 這是檢視⼀個物件是否是可迭代物件的第⼀種辦法. 我們還可以通過isinstence()函式來查 看⼀個物件是什麼型別的
l = [1,2,3]
l_iter = l.__iter__()
from collections import Iterable
from collections import Iterator
print(isinstance(l,Iterable)) #True
print(isinstance(l,Iterator)) #False
print(isinstance(l_iter,Iterator)) #True
print(isinstance(l_iter,Iterable)) #True
綜上. 我們可以確定. 如果物件中有__iter__函式. 那麼我們認為這個物件遵守了可迭代協議. 就可以獲取到相應的迭代器. 這⾥的__iter__是幫助我們獲取到物件的迭代器. 我們使⽤迭代 器中的__next__()來獲取到⼀個迭代器中的元素. 那麼我們之前講的for的⼯作原理到底是什 麼? 繼續看程式碼
s = "我愛北京天安⻔"
c = s.__iter__() # 獲取迭代器
print(c.__next__()) # 使⽤迭代器進⾏迭代. 獲取⼀個元素 我
print(c.__next__()) # 愛
print(c.__next__()) # 北
print(c.__next__()) # 京
print(c.__next__()) # 天
print(c.__next__()) # 安
print(c.__next__()) # ⻔
print(c.__next__()) # StopIteration
for迴圈的機制:
for i in [1,2,3]:
print(i)
lst = [1,2,3]
lst_iter = lst.__iter__()
while True:
try:
i = lst_iter.__next__()
print(i)
except StopIteration:
break
總結:
Iterable: 可迭代物件. 內部包含__iter__()函式
Iterator: 迭代器. 內部包含__iter__() 同時包含__next__().
迭代器的特點:
- 1. 節省記憶體.
- 2. 惰性機制
- 3. 不能反覆, 只能向下執⾏.
我們可以把要迭代的內容當成⼦彈. 然後呢. 獲取到迭代器__iter__(), 就把⼦彈都裝在彈夾 中. 然後發射就是__next__()把每⼀個⼦彈(元素)打出來. 也就是說, for迴圈的時候. ⼀開始的 時候是__iter__()來獲取迭代器. 後⾯每次獲取元素都是通過__next__()來完成的. 當程式遇到 StopIteration將結束迴圈.