一、 函數名的使用注意.
函數名是⼀個變量, 但它是⼀個特殊的變量, 與括號配合可以執⾏函數的變量。
1. 函數名可以賦值給其他變量
2. 函數名可以當做容器類的元素
3. 函數名可以當做函數的參數
4. 函數名可以作爲函數的返回值
二、 閉包
什麼是閉包? 閉包就是內層函數對外層函數(非全局)的變量的引⽤。示例如下:
def func1():
name = "倚窗頻頻醉夕陽"
def func2():
print(name) # 閉包
func2()
func1()
我們可以使⽤__closure__來檢測函數是否是閉包. 使⽤函數名.__closure__返回cell就是
閉包,返回None就不是閉包,示例:
def func1():
name = "倚窗頻頻醉夕陽"
def func2():
print(name) # 閉包
func2()
print(func2.__closure__)
func1()
結果:
在函數外邊調用內部函數:
def outer():
name = "昔時織就相思網"
# 內部函數
def inner():
print(name)
return inner
fn = outer() # 訪問外部函數, 獲取到內部函數inner的函數地址
fn() # 訪問內部函數
結果:
如果多層嵌套只需要⼀層⼀層的往外層返回就可以了,如:
def func1():
def func2():
def func3():
print("萬里雲天萬里霜")
return func3
return func2
func1()()()
結果:
我們之前說過, 如果⼀個函數執行完畢. 則這個函數中的變量以及局部命名空間中的內容都將會被銷燬. 在閉包中, 如果變量被銷燬了,那內部函數將不能正常執⾏。所 以python規定, 如果你在內部函數中訪問了外層函數中的變量,那麼這個變量將不會消亡,將會常駐在內存中. 也就是說,使⽤閉包, 可以保證外層函數中的變量在內存中常駐。 這樣做有什麼好處呢? 非常⼤的好處,比如說你做一個爬蟲程序需要爬取某網站的一部分內容,將它傳給一個局部變量,在全局訪問時就不用再執⾏⾮常耗時的網絡連接操作了。總之,一句話: 閉包的作⽤就是讓⼀個變量能夠常駐內存,供後⾯的程序使用。
三. 迭代器
我們之前⼀直在⽤可迭代對象進⾏迭代操作,那麼到底什麼是可迭代對象. ⾸先我們先回顧⼀下⽬前我們所熟知的可迭代對象有哪些:str, list, tuple, dict, set.
那爲什麼我們可以稱他們爲可迭代對象呢? 因爲他們都遵循了可迭代協議. 什麼是可迭代協議. ⾸先我們先看以下錯誤代碼:
for i in 123:
print(i)
注意看報錯信息中有這樣⼀句話. ‘int’ object is not iterable . 翻譯過來就是整數類型對象
是不可迭代的。iterable表⽰可迭代的,表⽰可迭代協議. 那麼如何進⾏驗證你的數據類型是否符合可迭代協議?
我們可以通過dir函數來查看類中定義好的所有⽅法.如:
print(dir(str)) # 打印類中聲明的⽅法和函數
結果:
查看一個對象是否是可迭代對象方法
1.用dir()函數在打印結果中. 尋找__iter__ ,如果能找到,那麼這個類的對象就是⼀個可迭代對象.
2.通過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)
使⽤while循環+迭代器來模擬for循環:
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__().
迭代器的特點:
- 節省內存.
- 惰性機制
- 不能反覆, 只能向下執⾏.
我們可以把要迭代的內容當成⼦彈,然後獲取到迭代器__iter__(), 就把⼦彈都裝在彈夾中,然後發射就是__next__()把每⼀個⼦彈(元素)打出來。即 for循環的時候,⼀開始時是__iter__()來獲取迭代器,後⾯每次獲取元素都是通過__next__()來完成的,當程序遇到StopIteration將結束循環。