【python基礎】五、python之裝飾器 (劃重點)

內部函數

  • 函數裏面 定義的 函數 --> 內部函數
    • 內部函數 修改 外部的變量 nonlocal
    • 內部函數 修改 全局的變量 global
a = 100


def func():
    b = 99
    def func_son():
        global a
        nonlocal b
        c = 88
        b += 1
        a += 1
        print(a, b, c)
  • globals() # 查看全局變量、函數
  • locals() # 查看內部變量、函數

閉包

  • 是什麼?
    • 函數中 的概念
    • 調用 函數的內部函數、內部變量
    • 函數返回自己的內部函數名,這就是閉包

    return 內部函數名

def func():
    def func_son():
        a = 10
        print(a)
    return func_son     # 不加(), 返回的是函數,不是調用函數
    
x = func()      # x 即爲 func_son
x()             # 給x加() 即 調用 func_son()

閉包的參數、變量

  • 閉包的作用域
    • 內部函數每次重新加載,但是 內部函數 訪問的仍是同一個外部函數

裝飾器

  • 應用廣泛,依賴閉包,是在閉包的基礎上的升級

條件一 函數作爲參數
條件二 閉包的特點

def decrator(func):  # 定義一個裝飾器
    a = 100
    def wrapper():  # 包裝 裝飾
        func()          # 調用被裝飾函數,保持其原功能
        print(' wrapper print a :', a)
    return wrapper
    
decrator(xxx)       # 傳入函數名 作爲參數

如何使用裝飾器 @

  • 在簡單函數上面 @裝飾器名字
# 使用裝飾器
@decrator
def house():
    print('i am 毛坯房')

house()

假如在開發完成後,發現house()函數還有不足,需要豐富一下。

  • 更改原函數 – 不可取

    • 不一定所有調用原函數都需要更改
  • 新增一個函數 – 不可取

    • 需要改 原來調用 house()的代碼

裝飾器 在不改變原函數名、原函數體 的情況下,對函數功能進行修改

# 完整
def decrator(func):  # 定義一個裝飾器
    a = 100
    print('wrapper 外層打印 仍然 執行 ')
    def wrapper():  # 包裝 裝飾
        print(' wrapper print a :', a)
        func()
        print(' 裝飾器在原函數的基礎上,增加了一個 a:{} 的輸出 '.format(a))

    print('即使不調用,由於@decrator,wrapper 外層打印 仍然執行 ')
    return wrapper


# 使用裝飾器
@decrator
def house():
    print(' house() :i am 毛坯房, 原函數,保持原功能')


# house()
  • @decrator 步驟分析
  1. 將其下方函數,作爲參數 傳給decrator()
  2. 底層 默執行decrator()函數,裏面的代碼
  3. 執行到 wrapper(), 加載wrapper內容(未執行)
  4. 最後 return wrapper
  5. 默認 同名的house 接收 返回的wrapper
    • 打印 wrapper 地址id
    • 打印 此時的 新house 地址id
  6. 下面的新house 即爲 wrapper, 其中調用了原house

帶有參數的 原函數

  • wrapper 也傳入同樣參數即可:
def decrator(func):  # 定義一個裝飾器
    def wrapper(x):  # 包裝 裝飾
        func(x)          # 調用被裝飾函數,保持其原功能
        print(' wrapper print a :', a)
    return wrapper

萬能 傳入參數

  • 可變參數
def decrator(func):  # 定義一個裝飾器
    def wrapper(*args, **kwargs):  # 包裝 裝飾
        func(*args, **kwargs)          # 調用被裝飾函數,保持其原功能
        print(' wrapper print a :', a)
    return wrapper

兩層裝飾器

@decrator2
@decrator1
house()

首先 近的decrator1 生效,
然後 decrator2 生效

  • 可以分析:
  1. decrator2 先裝飾完
  2. decrator1 裝飾 被 decrator2 裝飾過的house
  3. 調用的是 被 decrator1 裝飾過的 house
  4. 相當於 func(func1(func2()))

裝飾器 自帶 參數

  • 只要裝飾器自帶參數
  • 兩層裝飾器!
def decrator_outer(a):  # 接收 裝飾器 參數
    # 原 裝飾器
    def decrator(func):  # 接收 函數
        def wrapper(*args, **kwargs):  # 接收 函數參數
            func(*args, **kwargs)  
            print(a)# 調用被裝飾函數,保持其原功能
        return wrapper
    # 返回原 裝飾器
    return decrator
    
@decrator_outer(3)


在b站學習中,學習鏈接

個人主頁

歡迎 批評 指正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章