python之函式閉包、可迭代物件和迭代器
一、函式名的應用
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
# 1,函式名就是函式的記憶體地址,而函式名()則是執行這個函式。 def func(): return print(func) # 返回一個地址 # 2,函式名可以作為變數。 def func1(): print(666) f1 = func1 f2 = f1 f2() # 就等於func1() 此時執行函式 # 3,函式名可以作為函式的引數。 def func1(): print(666) def func2(x): x() func2(func1)# 輸出666 func1作為實參傳進func2中,此時在func2中x()等於func1() # 4,函式名可以當做函式的返回值。 def wraaper(): def inner(): print(666) return inner ret = wraaper() # 執行函式wraaper(),得到返回值inner賦值給ret,這個inner是函式名 ret() # 輸出666,ret()等於inner() # (注意:這裡要呼叫inner()只能是用ret(),因為inner()是wraaper()的巢狀函式,在全域性名稱空間中並沒有宣告,所以直接用inner()不能執行,)def func2(): print('in func2') def func3(x): print('in func3') return x f = func3(func2) # 給func3傳進一個引數func2,返回func2賦值給f f() # f()等於func2() # 5,函式名可以作為容器類型別的元素。 def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1, f2, f3] d= {'f1': f1, 'f2': f2, 'f3': f3} # 呼叫 l[0]() # 輸出 f1 d['f2']() # 輸出 f2 def func1(): print('in func1') def func2(): print('in func2') def func3(): print('in func3') def func4(): print('in func4') l1 = [func1,func2,func3,func4] #呼叫 for i in l1: i() # 像上面的函式名這種,稱為第一類物件。 # 第一類物件(first-class object)指: # 1.可在執行期建立 # 2.可用作函式引數或返回值 # 3.可存入變數的實體。 # (如果不明白,那就記住一句話,就當普通變數用)
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
6、globals() locals()
globals() #返回全域性變數(包含內建函式)的一個字典。
locals() #返回當前位置的變數的字典。
例如:
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
def func1(): a = 2 b = 3 print(globals()) # 此時globals()在區域性名稱空間中,但也是返回全域性名稱空間的一個字典 print(locals()) # 此時locals()在區域性名稱空間中,所以返回的是區域性名稱空間的一個字典{'b': 3, 'a': 2} print(globals()) # 此時globals()在全域性名稱空間中,返回全域性名稱空間的一個字典 print(locals()) # 此時locals()在全域性名稱空間中,所以返回的是全域性名稱空間的一個字典 func1() # 結果: # {'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} # {'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} # {'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} # {'b': 3, 'a': 2}
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
總結:
globals()無論在哪個名稱空間,返回的都是全域性名稱空間的一個字典
locals()在哪個名稱空間就返回哪個名稱空間的字典
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
def func1(): a = 2 b = 3 def inner(): c = 5 d = 6 print(globals()) #{'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} print(locals()) #{'c': 5, 'd': 6} inner() func1()
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
二、閉包
1、內層函式引用外層函式的變數(非全域性變數),這樣該內部函式稱就稱為閉包函式。
(我們都知道函式內的變數我們要想在函式外部用,可以直接返回這個變數,那麼如果我們想在函式外部呼叫函式內部的函式呢?
就把這個函式的名字返回就好了,這是閉包函式最常用的用法)
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
def wraaper(): name = '鬼見愁' def inner(): print(name) return inner f = wraaper() f()
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
2、判斷閉包函式的方法__closure__
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
# 1,是閉包返回值會有cell元素 def wraaper(): name = '鬼見愁' def inner(): print(name) print(inner.__closure__) return inner f = wraaper() f() # 2,不是閉包就會返回None name = '鬼見愁' def wraaper(): def inner(): print(name) print(inner.__closure__) # None return inner f = wraaper() f() name = '番薯' def wraaper(n): n = '番薯' def inner(): print(n) print(inner.__closure__) # cell at 0x000002AD93BF76D8 inner() return inner wraaper(name)
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
'''
閉包作用:
當程式執行時,遇到了函式執行,他會在記憶體中開闢一個空間,區域性名稱空間,
如果這個函式內部形成了閉包,
那麼它就不會隨著函式的結束而消失。
'''
什麼時候用到閉包?
例如:爬蟲,裝飾器等
下面是一個爬蟲的小案例:
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
from urllib.request import urlopen def index(): url = "http://www.xiaohua100.cn/index.html" def get(): return urlopen(url).read() return get xiaohua = index() # get content = xiaohua() # get() print(content.decode('utf-8'))
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
三、可迭代物件
for i in 'abc':
print(i)
for i in 123:
print(i) # 'int' object is not iterable表示不是可迭代物件
物件內部含有__iter__方法就是可迭代物件.
可迭代物件滿足可迭代協議。
可迭代物件:str list dict,tuple,set,range()
dir() :返回一個列表,列表裡面包含了傳入的引數的屬性、方法
s1 = 'strs'
print(dir(s1))
判斷一個物件是否是可迭代物件:
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
# 第一個方法 s1 = 'abc' dic = {'name':'xiaoming'} print('__iter__' in dir(s1)) print('__iter__' in dir(dic)) # 第二種方法 from collections import Iterable #判斷是否為可迭代物件 from collections import Iterator #判斷是否為迭代器 print(isinstance('xiaoming',Iterable)) # True print(isinstance('xiaoming',Iterator)) # False print(isinstance('xiaoming',str)) # True #isinstance() 應用比type()更廣泛,isinstance()不僅可以判斷你是不是可迭代物件, #也可判斷你是否迭代器,還可以判斷你是什麼型別的資料等等,而#type()只能判斷你是什麼資料型別
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
四、迭代器
1、物件內部含有__iter__方法且含有__next__方法就是迭代器。
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
#檔案控制代碼是迭代器: f = open('register', encoding='utf-8') print('__iter__' in dir(f)) #True print('__next__' in dir(f)) #True #字典是可迭代物件,不是迭代器。 print('__iter__' in dir(dict)) #True print('__next__' in dir(dict)) #False
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
2、可迭代物件與迭代器的區別:
1,可迭代物件不能取值,迭代器是可以取值的。
(我們知道字典列表都是可迭代物件,為什麼它們能取值呢?這是因為為了方便我們操作,我們設定了
索引(鍵)用來操作字典列表取值,如果沒有人為為它們設定的索引(鍵),它們是不能取值的)
2, 迭代器非常節省記憶體。
3,迭代器每次只會取一個值。
4,迭代器單向的,一條路走到頭。
3、可迭代物件 --->(轉化成)迭代器
lis = [1, 2, 3] # 可迭代物件 ite1 = lis.__iter__() # 迭代器 <list_iterator object at 0x0000027A183BFFD0> ite1 = iter(lis) # 迭代器 <list_iterator object at 0x0000027A183BFFD0> print(ite1)
4、迭代器如何取值? next一次,取一個值
print(ite1.__next__()) print(ite1.__next__()) print(ite1.__next__())
5、while迴圈模擬for迴圈機制
1,將可迭代物件轉化成迭代器。
2,呼叫__next__方法取值。
3,利用異常處理停止報錯。
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
s1 = 'abcdefg' iter1 = s1.__iter__() while 1: try: print(iter1.__next__()) except StopIteration: break
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
一、函式名的應用
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
# 1,函式名就是函式的記憶體地址,而函式名()則是執行這個函式。 def func(): return print(func) # 返回一個地址 # 2,函式名可以作為變數。 def func1(): print(666) f1 = func1 f2 = f1 f2() # 就等於func1() 此時執行函式 # 3,函式名可以作為函式的引數。 def func1(): print(666) def func2(x): x() func2(func1) # 輸出666 func1作為實參傳進func2中,此時在func2中x()等於func1() # 4,函式名可以當做函式的返回值。 def wraaper(): def inner(): print(666) return inner ret = wraaper() # 執行函式wraaper(),得到返回值inner賦值給ret,這個inner是函式名 ret() # 輸出666,ret()等於inner() # (注意:這裡要呼叫inner()只能是用ret(),因為inner()是wraaper()的巢狀函式,在全域性名稱空間中並沒有宣告,所以直接用inner()不能執行,) def func2(): print('in func2') def func3(x): print('in func3') return x f = func3(func2) # 給func3傳進一個引數func2,返回func2賦值給f f() # f()等於func2() # 5,函式名可以作為容器類型別的元素。 def f1(): print('f1') def f2(): print('f2') def f3(): print('f3') l = [f1, f2, f3] d = {'f1': f1, 'f2': f2, 'f3': f3} # 呼叫 l[0]() # 輸出 f1 d['f2']() # 輸出 f2 def func1(): print('in func1') def func2(): print('in func2') def func3(): print('in func3') def func4(): print('in func4') l1 = [func1,func2,func3,func4] #呼叫 for i in l1: i() # 像上面的函式名這種,稱為第一類物件。 # 第一類物件(first-class object)指: # 1.可在執行期建立 # 2.可用作函式引數或返回值 # 3.可存入變數的實體。 # (如果不明白,那就記住一句話,就當普通變數用)
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
6、globals() locals()
globals() #返回全域性變數(包含內建函式)的一個字典。
locals() #返回當前位置的變數的字典。
例如:
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
def func1(): a = 2 b = 3 print(globals()) # 此時globals()在區域性名稱空間中,但也是返回全域性名稱空間的一個字典 print(locals()) # 此時locals()在區域性名稱空間中,所以返回的是區域性名稱空間的一個字典{'b': 3, 'a': 2} print(globals()) # 此時globals()在全域性名稱空間中,返回全域性名稱空間的一個字典 print(locals()) # 此時locals()在全域性名稱空間中,所以返回的是全域性名稱空間的一個字典 func1() # 結果: # {'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} # {'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} # {'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} # {'b': 3, 'a': 2}
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
總結:
globals()無論在哪個名稱空間,返回的都是全域性名稱空間的一個字典
locals()在哪個名稱空間就返回哪個名稱空間的字典
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
def func1(): a = 2 b = 3 def inner(): c = 5 d = 6 print(globals()) #{'__name__': '__main__', '__doc__': None(後面還有一大推東西,省略)...} print(locals()) #{'c': 5, 'd': 6} inner() func1()
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
二、閉包
1、內層函式引用外層函式的變數(非全域性變數),這樣該內部函式稱就稱為閉包函式。
(我們都知道函式內的變數我們要想在函式外部用,可以直接返回這個變數,那麼如果我們想在函式外部呼叫函式內部的函式呢?
就把這個函式的名字返回就好了,這是閉包函式最常用的用法)
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
def wraaper(): name = '鬼見愁' def inner(): print(name) return inner f = wraaper() f()
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
2、判斷閉包函式的方法__closure__
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
# 1,是閉包返回值會有cell元素 def wraaper(): name = '鬼見愁' def inner(): print(name) print(inner.__closure__) return inner f = wraaper() f() # 2,不是閉包就會返回None name = '鬼見愁' def wraaper(): def inner(): print(name) print(inner.__closure__) # None return inner f = wraaper() f() name = '番薯' def wraaper(n): n = '番薯' def inner(): print(n) print(inner.__closure__) # cell at 0x000002AD93BF76D8 inner() return inner wraaper(name)
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
'''
閉包作用:
當程式執行時,遇到了函式執行,他會在記憶體中開闢一個空間,區域性名稱空間,
如果這個函式內部形成了閉包,
那麼它就不會隨著函式的結束而消失。
'''
什麼時候用到閉包?
例如:爬蟲,裝飾器等
下面是一個爬蟲的小案例:
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
from urllib.request import urlopen def index(): url = "http://www.xiaohua100.cn/index.html" def get(): return urlopen(url).read() return get xiaohua = index() # get content = xiaohua() # get() print(content.decode('utf-8'))
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
三、可迭代物件
for i in 'abc':
print(i)
for i in 123:
print(i) # 'int' object is not iterable表示不是可迭代物件
物件內部含有__iter__方法就是可迭代物件.
可迭代物件滿足可迭代協議。
可迭代物件:str list dict,tuple,set,range()
dir() :返回一個列表,列表裡面包含了傳入的引數的屬性、方法
s1 = 'strs'
print(dir(s1))
判斷一個物件是否是可迭代物件:
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
# 第一個方法 s1 = 'abc' dic = {'name':'xiaoming'} print('__iter__' in dir(s1)) print('__iter__' in dir(dic)) # 第二種方法 from collections import Iterable #判斷是否為可迭代物件 from collections import Iterator #判斷是否為迭代器 print(isinstance('xiaoming',Iterable)) # True print(isinstance('xiaoming',Iterator)) # False print(isinstance('xiaoming',str)) # True #isinstance() 應用比type()更廣泛,isinstance()不僅可以判斷你是不是可迭代物件, #也可判斷你是否迭代器,還可以判斷你是什麼型別的資料等等,而#type()只能判斷你是什麼資料型別
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
四、迭代器
1、物件內部含有__iter__方法且含有__next__方法就是迭代器。
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
#檔案控制代碼是迭代器: f = open('register', encoding='utf-8') print('__iter__' in dir(f)) #True print('__next__' in dir(f)) #True #字典是可迭代物件,不是迭代器。 print('__iter__' in dir(dict)) #True print('__next__' in dir(dict)) #False
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
2、可迭代物件與迭代器的區別:
1,可迭代物件不能取值,迭代器是可以取值的。
(我們知道字典列表都是可迭代物件,為什麼它們能取值呢?這是因為為了方便我們操作,我們設定了
索引(鍵)用來操作字典列表取值,如果沒有人為為它們設定的索引(鍵),它們是不能取值的)
2, 迭代器非常節省記憶體。
3,迭代器每次只會取一個值。
4,迭代器單向的,一條路走到頭。
3、可迭代物件 --->(轉化成)迭代器
lis = [1, 2, 3] # 可迭代物件 ite1 = lis.__iter__() # 迭代器 <list_iterator object at 0x0000027A183BFFD0> ite1 = iter(lis) # 迭代器 <list_iterator object at 0x0000027A183BFFD0> print(ite1)
4、迭代器如何取值? next一次,取一個值
print(ite1.__next__()) print(ite1.__next__()) print(ite1.__next__())
5、while迴圈模擬for迴圈機制
1,將可迭代物件轉化成迭代器。
2,呼叫__next__方法取值。
3,利用異常處理停止報錯。
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)
s1 = 'abcdefg' iter1 = s1.__iter__() while 1: try: print(iter1.__next__()) except StopIteration: break
![複製程式碼](http://common.cnblogs.com/images/copycode.gif)