1. 程式人生 > 實用技巧 >python 函數語言程式設計-閉包

python 函數語言程式設計-閉包

1、基礎知識保證我們寫出業務程式碼,而且我們不考慮太多的封裝性;高階知識保證,可以去更好的封裝包,類庫,提供給其他人使用

2、高階知識

  • 函數語言程式設計
  • 閉包

  • 什麼是函數語言程式設計?
  • 什麼是閉包?

3、python中一切結皆物件。所以函式也是物件。

  • 函式可以賦值給一個變數,變數的型別是個函式function
  • def curve_pre():
        pass
    a = curve_pre
    print(type(a))
    # [Running] python -u "/Users/anson/Documents/Project/python_ToolCodes/test20.py"
    # <type 'function'>

  • 呼叫函式變數,執行該函式,返回的該函式計算結果
  • def curve_pre():
        def curve(x):
            return x*x
        return curve
    
    f = curve_pre()
    print(f)#返回的是一個函式&函式可以賦值給一個變數
    print(f(2))#呼叫返回的函式
    # [Running] python -u "/Users/anson/Documents/Project/python_ToolCodes/test20.py"
    # <function curve at 0x1078b0140>
    # 4

  • 變數a從內到外層找,逐漸從小作用域到大作用域去找,從精確作用域到概括作用域,即優先順序從內層函式區域性變數->外層函式區域性變數->最外層變數
  • a = 100#3、外層沒有,去更外層找
    def curve_pre():
        a = 50#2、沒有內層a,去外層找a
        def curve(x):
            a = 1#1、先找這個a
            return a*x*x
        return curve
    
    f = curve_pre()
    print(f)
    print(f(2))

    由此引入什麼是閉包?閉包=函式+環境變數,把a定義在標誌1的位置,也就是函式內部,不叫閉包,頂多算個函式呼叫,定義在函式的外部,也就是3的位置,那也不叫閉包

  • 放在內層2的位置,為什麼叫閉包?
    def curve_pre():
        a 
    = 50 def curve(x): return a*x*x return curve a = 1 f = curve_pre() print(f.__closure__) print(f.__closure__[0].cell_contents) print(f(2)) # [Running] python -u "/Users/anson/Documents/Project/python_ToolCodes/test20.py" # (<cell at 0x103603750: int object at 0x7fe15b708d68>,) # 50 # 200

    改了a=1,也不起作用,前面說過的使用優先順序。注意閉包的內容,f.__closure__,是把函式呼叫的現場給儲存下來了閉包=函式+環境變數(a=50,func=curve)

  • 函式閉包的需要注意什麼? 
  • def f0():
        a = 50
        def f1(x):
            a=1#造成了不是閉包,閉包=環境變數(f0()層定義的a=50)+函式f1(x)
            return a*x*x
        return f1
    f = f0()
    print(f.__closure__)
    print(f.__closure__[0].cell_contents)
    print(f(2))
    # [Running] python -u "/Users/anson/Documents/Project/python_ToolCodes/test21.py"
    # None
    # Traceback (most recent call last):
    #   File "/Users/anson/Documents/Project/python_ToolCodes/test21.py", line 10, in <module>
    #     print(f.__closure__[0].cell_contents)
    # TypeError: 'NoneType' object has no attribute '__getitem__'

    正確的做法是,不要再內層定義a,這樣就沒有環境變量了!!!!!!,閉包的2個必要元素缺少一個了,怎麼還會是閉包!!!!!!

  • def f0():
        a = 50
        def f1(x):
            c=1
            return a*x*x
        return f1
    f = f0()
    print(f.__closure__)
    print(f.__closure__[0].cell_contents)
    print(f(2))
    # [Running] python -u "/Users/anson/Documents/Project/python_ToolCodes/test21.py"
    # (<cell at 0x10a3df750: int object at 0x7f963de06158>,)
    # 50
    # 200

    這樣改或者註釋掉f1(x)中定義的a 就可以了

  • 閉包是用來幹什麼的,使用場景是什麼?
  • 計算旅行者當前所處的位置,起點origin=0
    非閉包
    origin = 0
    def go(step):
        global origin #宣告origin為gloabl,記錄旅行者當前的位置
        new_pos = origin+step
        origin = new_pos
        return new_pos
    
    print(go(3))
    print(go(2))
    輸出:
    3
    5
    閉包
    origin  = 0
    
    def go_pre(pos):
        def go(step):
            nonlocal pos#宣告pos 為 nonlocal
            new_pos = pos + step
            pos     = new_pos
            return new_pos
        return go
    
    f = go_pre(origin)
    print(f(3))
    print(f(2))
    
    輸出
    3
    5
    ⚠️python2沒有nonlocal,python3才有

  • 閉包主要用在Javascript 和python python 中強調的是閉包中的環境變數。