1. 程式人生 > 實用技巧 >8-函式高階

8-函式高階

函式高階使用

  • f:既是函式名稱,也是指向函式的一個變數

  • 所有指向函式的變數都可以呼叫該函式

  • 回撥函式

    • m1(3, m2)
    • m1是普通函式,m2作為引數,在m1內部呼叫m2

函式作用域

  • 作用域:起作用的範圍
  • 區域性變數與全域性變數
    • 區域性變數:函式內部定義的變數,只能在函式內部使用
      • nonlocal b
      • 呼叫非本地(函式內部)的最近的b
      • 優點:不會被外部干擾
      • 缺點:記憶體會被回收(變數會被刪除)
    • 全域性變數:函式外部定義的變數,具有全域性作用域
      • 預設不可以修改全域性變數
      • global 作用是a使用的是全域性變數a
        • global a
      • 優點:記憶體不會被回收(變數不會被刪除)
      • 缺點:可能會被幹擾

函式巢狀和閉包

  • 函式巢狀

    • def f1():
          print('f1')
          def f2():
              print('f2')
          # f2()
          return f2
      res = f1()  # res = f2
      res()  # 等價於f2()
      
    • 傳參

      • f(3)(4)
  • 函式閉包

    • 閉包:函式巢狀,把內部函式返回,可以讓外部函式中的引數或變數不被釋放(讓變數不消失)

    • 閉包的特點:不會被外部干擾,記憶體也不會被回收

      • def out():
            p = 10
            def inner():
                nonlocal p
                p += 1
                print('p=', p)
            return inner
        
        f = out()  # f = inner
        f()  # 11,相當於inner()
        f()  # 12
        f()  # 13
        

生成器擴充套件

  • 生成器和迭代器很相似,其實它們都是消費者和生產者模型,都是使用者通過next()方法來獲得資料,而生成器和迭代器都是隻有使用者在呼叫next()時才返回資料。不同的是迭代器是通過自己實現next()方法來逐步返回資料,而生成器則使用yield自動完成了提供資料並且讓程式進入wait狀態,等待使用者的進一步操作,所以生成器更加靈活和方便
  • 生成器的方法
    • next()方法
    • send(msg)方法
      • 當使用send(msg)傳送訊息給生成器時,wait_and_get會檢測到這個資訊,然後喚醒生成器,同時該方法獲取msg並賦值給x
      • g.send(5)
    • throw()方法
      • 生成器提供throw()方法從生成器內部來引發異常,從而控制生成器的執行
      • h.throw(GeneratorExit)
    • close()方法
      • 當使用close()方法時,生成器會直接從當前狀態退出
    • 生成器的用途
      • 節省記憶體
      • 線性遍歷訪問資料
        • 生成器可以將非線性化的處理轉換成線性化的方式,典型的例子就是對二叉樹的訪問。傳統的方法是使用遞迴函式來訪問和處理,需要將處理方法放到訪問的過程中,既容易出錯也不清晰。比較好的方法是先將樹的節點訪問轉換成線性,然後在外面遍歷每一個節點,這樣一來,處理每個節點的過程不需要放到訪問每個節點的diamagnetic中去,更加清晰

列表生成器&列表生成式

  • 列表生成式

    • ages = [i * 10 for i in range(2, 5) if 2 < i < 4]
    • l3 = [i+j for i in l1 for j in l2]
  • 字典生成式

    • d = {i: i+1 for i in range(1, 4)} # {1: 2, 2: 3, 3: 4}
  • 列表生成器

    • ages = (i for i in range(5)) # <generator object <genexpr> at 0x0000015A66E54AC8>

    • 生成器物件:可以不一次性佔用太多的記憶體空間,我們一般需要一個一個元素取出來

    • next函式

      • print(next(ages))  # 0
        print(next(ages))  # 1
        print(next(ages))  # 2
        
    • 生成器函式

      • 生成器函式:在普通函式中包含yield關鍵字,則是生成器函式
      • yield:
        • 1.寫在函式中,讓普通函式變成生成器函式
        • 2.可以返回值,但是不會退出函式
        • 3.需要結合next使用,每次使用next,則會執行至下一個yield

計算程式碼耗時

  • 計算程式碼耗時

    • import time
      start = time.time()  # 獲取當前時間
      for i in range(1000):
          pass
      end = time.time()
      print(end - start)
      

可迭代物件&迭代器

  • from collections.abc import Iterable # 可迭代物件

  • from collections.abc import Iterator # 迭代器

  • 可迭代物件

    • 可迭代物件:只要可以使用for-in迴圈,就是可迭代物件
    • 有:list, tuple, dict, set, str,generator
  • isinstance(): 檢測某個物件是否屬於某個類

    • print(isinstance([1, 3], Iterable)) # True
  • 迭代器

    • 迭代器:既要能用for-in迴圈,且可以使用next呼叫

    • iter():將可迭代物件變成迭代器

      • l = [1, 3, 4]
        l2 = iter(l)
        print(l2)  # <list_iterator object at 0x0000017DB5C4BE48>
        print(next(l2))  # 1
        print(list(l2))  # [3, 4], 1已經被取出了
        
    • _iter_()將可迭代物件變成迭代器

      • l1 = [1, 3, 4]
        l1_iter = l1.__iter__()
        print(type(l1_iter))  # <class 'list_iterator'>
        for x in l1_iter:
            print(x)
        

偏函式

print(int('10'))
print(int('10', base=2))  # 2,將10看成是二進位制
print(int('1010', base=8))  # 520

import functools
int2 = functools.partial(int, base=2)
print(int2('1010'))  # 10