1. 程式人生 > >閉包(閉包=函式+環境變數)

閉包(閉包=函式+環境變數)

 擴充

  •  函數語言程式設計(淡化)
  •  函式只是一段可執行的程式碼,不可以例項化,並不是物件
  •   一切皆物件、python    另外一個函式的引數,傳遞到另外的函式裡;把一個函式當做是另一個函式的返回結果:
     
def a():
    pass
print(type(a))
#>>><class 'function'>

步入正題:閉包=函式+環境變數(函式定義時候的環境變數,不能是全域性變數)

閉包是函數語言程式設計的一種

1、閉包的形式及使用

#閉包
def curve_pre():
    b=25
    def curve(x):#曲線
        return b*x*x
    return curve

#curve()在外部不可以直接呼叫

b=10
f=curve_pre()
print(f.__closure__)#__closure__內建函式存放閉包的環境變數資訊,返回的是閉包
#>>>(<cell at 0x0261B750: int object at 0x6DF7BFC8>,)

print(f.__closure__[0].cell_contents)
#>>>25   輸出環境變數的值

f(2)#執行函式==>curve(2)
print(f(2))
#>>>100
#不會因為全域性變數而輸出40,而是使用環境變數a=25

__closure__內建函式存放閉包的環境變數資訊,返回的是閉包

__closure__[0].cell_contents
#>>>25   輸出環境變數的值

輸出結果

>>> 
<class 'function'>
(<cell at 0x0261B750: int object at 0x6DF7BFC8>,)
25
100

延伸:單個函式f1(),a是全域性變數,f1()函式在找不到a的值的情況下會呼叫全域性變數a=10

a=10
def f1(x):
    return a*x*x
f1(2)
print(f1(2))
#>>>40

閉包的經典誤區:

例子:

def f2():
    c=10
    def f3():
        c=20
        print(c)#②2>>>20
    print(c)#①1>>>10
    f3()
    print(c)#③3>>>10
f2()
    

輸出結果:

>>>10
20
10

改動判斷是不是閉包:

#改動判斷是不是閉包
def f2():
    c=10
    def f3():
        #此時將被python認為是一個區域性變數
        c=20
        return c
    return f3
w=f2()
print(w)
print(w.__closure__) #在這裡這個屬性__closure__是沒有的 

輸出:

>>><function f2.<locals>.f3 at 0x008AE030>
None

重點!!!:在這裡這個屬性__closure__是沒有的,其實因為c=20存在,它此時將被python認為是一個區域性變數,內部函式輸出的是區域性變數而不是環境變數,不滿足閉包的要求,所以實質上此時還不是一個閉包

再改進:

def f2():
    c=10
    def f3():
        #此時內部函式中只是引用了c
        d=20*c
        return c
    return f3
w=f2()
print(w)
print(w.__closure__)

輸出:

<function f4.<locals>.f5 at 0x08896E88>
(<cell at 0x0371FB10: int object at 0x6DF7BED8>,)

此時根據print(w.__closure__)返回的資訊(<cell at 0x0371FB10: int object at 0x6DF7BED8>,)得知是一個閉包

用閉包來解決一個問題:旅行者,每走一步加一,編寫函式得到當前的位置

1、非閉包形式解決:

origin=0
def go(stpe):
    global origin
    new_pos=origin+stpe
    origin=new_pos
    return new_pos
    
print(go(2))#>>>2
print(go(3))#>>>5
print(go(6))#>>>11

2、閉包形式解決:

origin1=0
def factory(pos):  
    def go1(stpe):
        #強制宣告pos不是區域性變數
        nonlocal pos
        new_pos=pos+stpe
        pos=new_pos
        return new_pos
    return go1

tourist=factory(origin1)
print(tourist(2))#>>>2
print(origin1)#>>>0
print(tourist.__closure__[0].cell_contents)#>>>2
print(tourist(3))#>>>5
print(origin1)#>>>0
print(tourist.__closure__[0].cell_contents)#>>>5
print(tourist(6))#>>>11
print(origin1)#>>>0
print(tourist.__closure__[0].cell_contents)#>>>11

輸出:
 

2
0
2
5
0
5
11
0
11