1. 程式人生 > >day 10 函式名的運用,閉包,迭代器

day 10 函式名的運用,閉包,迭代器

函式名的本質

函式名本質上就是函式的記憶體地址

函式名的五種運用:

 1、函式名是一個變數

def func():
    print(666)
print(func)    # 函式的記憶體地址 <function func at 0x000002B6D2559AE8>

2、函式名可以當做變數賦值

def func():
    print(666)
f1 = func
f2 = f1
f2()                

3、函式名可以當做容器類資料型別的元素

複製程式碼
def func1():
    print(111)
def func2():
    print(222)
def func3():
    print(333)
l1 = [func1, func2 ,func3]
for i in l1:
    i()
複製程式碼

4、函式名可以當做函式的引數

def func(x):   #  x  == func1
    x()
    print('in func')
def func1():
    print('in func1')
func(func1)

5、函式名可以當做函式的返回值

複製程式碼
def func(x):  # x ---> func1
    return x  # func1

def func1():
    print('in func1')

ret = func(func1)  #  ret = func1
ret()     # func1()
func(func1)()  # x() == func1()
複製程式碼

滿足3,4,5 函式名也稱為第一類物件

閉包:

什麼是閉包:

複製程式碼
def func():
    name = 666
    print(111)
    def func1():
        print(name)  # 這就是閉包, 內層函式對外層函式(非全域性)變數的引用
    func1()
func()
複製程式碼
1,內層函式對外層函式(非全域性)變數的引用。
2,閉包只存在於內層函式中。
3,函式都要逐層返回,最終返回給最外層函式。
複製程式碼
def func():
    name = 'alex'
    def inner():
        print(name)
    return inner           
f = func()    #  f = inner
f()
複製程式碼

閉包的判斷

f.__closure__[0].cell_contents   閉包引用的外部變數
複製程式碼
def func():
    name = 'alex'
    age = 19
    def inner():
        print(name)
        print(age)
    return inner
f = func()         # 定義f,因為f是閉包
# 獲取閉包引用的外層變數,如果不是閉包則報錯
print(f.__closure__[0].cell_contents)  #固定用法  19
print(f.__closure__[1].cell_contents)  # alex
複製程式碼

閉包有什麼用?

閉包:直譯器執行程式時,如果遇到函式,隨著函式的結束而關閉臨時名稱空間,但是!!!如果遇到閉包,有一個機制:那麼閉包的空間不會隨著函式的結束而關閉。

複製程式碼
def wrapper(step):
    num =1
    def inner():
        nonlocal num
        num += step
        print(num)     # 輸出 4   7   10  13  16
    return inner
f = wrapper(3)
j = 0
while j < 5:
    f()
    j += 1
複製程式碼

閉包就是在記憶體中開一個空間,常貯存一些內容,以便後續程式呼叫
閉包的應用:
1、裝飾器
2、爬蟲

迭代物件:
iterable: 可迭代物件
內部含有__iter__方法的就是可迭代物件,遵循可迭代協議
s1 = 'barry'
l1 = [1, 2, 3]
print('__iter__' in dir(s1))  # True  是可迭代物件

可迭代物件不能直接取值(含索引的迭代物件除外) ,需要轉換成迭代器才能取值

迭代器

迭代器:內部含有'__iter__'並且含有'__next__'方法的就是迭代器,遵循迭代器協議。

可迭代物件轉換成迭代器:

  可迭代物件.__iter__()

  obj = iter(可迭代物件)

 

判斷一個一個物件是否是迭代器(含iter,next)或迭代物件

 方法一:  看__iter__ , __next__  在不在dir() 裡面

s1 = 'abcdefg'
obj = iter(s1)    # 將s1轉換成迭代器
print('__iter__' in dir(s1))   # True
print('__iter__' in dir(obj))  # True
print('__iter__' in dir(s1) and '__next__' in dir(s1))  # False
print('__iter__' in dir(obj) and '__next__' in dir(obj)) # True
方法二:   isinstance(obj, Iterable/Iterator)
複製程式碼
s1 = 'abcdefg'
obj = iter(s1)    # 將s1轉換成迭代器
from collections import Iterable   # 迭代物件
from collections import Iterator   # 迭代器
print(isinstance(obj,Iterator))  # 判斷obj是否為迭代器     True
print(isinstance(obj,Iterable))  # 判斷obj是否為可迭代物件 True
print(isinstance(s1,Iterator))   # 判斷obj是否為迭代器     False
print(isinstance(s1,Iterable))   # 判斷obj是否為可迭代物件 True
複製程式碼
 

迭代器取值

s2 = [1, 2, 3]
obj = iter(s2)
print(obj.__next__())    # 方法一
print(next(obj))            # 方法二
type() isinstance()區別?

# type()只是判斷該物件的資料型別
# isinstance()不僅可以判斷該物件的資料型別,而且可以判斷其他很多

迭代器的作用:
1、節省記憶體
2、惰性機制 (netx())一下,出一個值
3、一條路走到黑,不走回頭路

While迴圈模擬for迴圈機制
複製程式碼
l1 = [i for i in range(10)]
obj = iter(l1)
while 1:
    try:     # 試一試,如果報錯就執行下面的命令
        print(next(obj))
    except StopIteration:  
        break
複製程式碼