1. 程式人生 > 實用技巧 >閉包函式,無參裝飾器,疊加多個裝飾器,有參裝飾器

閉包函式,無參裝飾器,疊加多個裝飾器,有參裝飾器

一、閉包函式

閉包函式=函式巢狀定義+函式物件+名稱空間與作用域
閉包函式
  閉:指的是該函式是定義在一個函式內部的函式
  包:值得是該函式訪問了一個來自於外層函式的變數
為函式體傳參:
方案一:直接使用引數的形式傳遞
def wrapper(x):
    print(x)

wrapper(111)
wrapper(222)
方案二:把函式體想要的引數包給它
def outter(x):
    # x = 111

    def wrapper():  # wrapper = 閉包函式的記憶體地址
        print(x)

    return wrapper  # 一定不要加括號
# return 閉包函式的記憶體地址 f1 = outter(111) # f = 閉包函式的記憶體地址 f2 = outter(222) # f = 閉包函式的記憶體地址

二、無參裝飾器

1、什麼是裝飾器
器:工具
裝飾:為被裝飾者新增額外的功能
2、為何要有裝飾器
軟體一旦上線執行之後,就應該遵循開放封閉原則:
1、開放指的是對拓展新功能開放
2、封閉指的是對修改原始碼封閉
定義裝飾器的目的:
定義裝飾器就是為了在遵循1和2的前提下來為其他函式新增新功能的
ps:
不修改被裝飾物件指的是定義與呼叫都不能修改
所以下述行為都違反了開放封閉原則:
1、修改被裝飾物件定義時的原始碼
2、修改被裝飾物件的呼叫方式
3、如何用裝飾器
  3.1 被裝飾器物件index如下:
import time

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

index(1,2)

  3.2為index新增新功能

 #方案一:直接修改原始碼為被裝飾物件index新增新功能
#問題:修改了原始碼
import time

def index(x,y):
    start_time = time.time()
    time.sleep(
1) print('index===>',x,y) stop_time = time.time() print('run time is: %s' %(stop_time - start_time)) index(1,2)
# 方案二:找到所有呼叫index的位置,然新增程式碼
#問題:需要寫好多段重複程式碼
import time

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

start_time = time.time()
index(1,2)
stop_time = time.time()
print('run time is: %s' %(stop_time - start_time))
#方案三:把裝飾功能寫到一個函式內
#問題:裝飾功能被寫死了,只能用來裝飾index函數了
import time

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

def wrapper():
    start_time = time.time()
    index(1,2)
    stop_time = time.time()
    print('run time is: %s' %(stop_time - start_time))

wrapper()
#方案四:把wrapper函式內的index修改為引數的形式
#問題:直接為wrapper函式傳參的方案不行,因為原函式的呼叫
           是在全域性呼叫index(1,2), 而現在的呼叫統一都變成了        wrapper(index),著修改被裝飾的呼叫方式

import time

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

def wrapper(func):
    start_time = time.time()
    func(1,2)
    stop_time = time.time()
    print('run time is: %s' %(stop_time - start_time))

wrapper(index)
#方案五:基於閉包函式把wrapper函式想要的引數包給它,然後基於函式物件把閉包函式wrapper返回到全域性,賦值給原函式名
#問題:把index偽裝成了wrapper,但偽裝的不夠像:引數的傳遞與原函式不一致
import time

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

def outter(func):
    # func = index
    def wrapper():
        start_time = time.time()
        func(1,2)
        stop_time = time.time()
        print('run time is: %s' %(stop_time - start_time))
    return wrapper

index=outter(index)

index()
#方案六:在方案五的基礎上基於*args,**kwargs把wrapper的引數偽裝成跟被裝飾函式一模一樣
#問題:返回值與原函式不一致
import time

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

def home(name):
    time.sleep(0.5)
    print('welcome %s to home page' %name)
    return 123

def outter(func):
    # func = index
    def wrapper(*args,**kwargs):
        start_time = time.time()
        func(*args,**kwargs)
        stop_time = time.time()
        print('run time is: %s' %(stop_time - start_time))
    return wrapper

index=outter(index)
home=outter(home)

# index(1,2)
res=home('egon')
print(res)
#方案七:在方案六的基礎上把wrapper函式的返回值與被裝飾函式保持一致
#問題:裝飾器的使用不夠簡潔
import time
from functools import wraps

def timmer(func):
    # func = index
    @wraps(func)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res=func(*args,**kwargs)
        stop_time = time.time()
        print('run time is: %s' %(stop_time - start_time))
        return res
    return wrapper

def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

def home(name):
    "home的文件註釋"
    time.sleep(0.5)
    print('welcome %s to home page' %name)
    return 123

index=timmer(index)
home=timmer(home)

# res=index(1,2)
# print(res)

# res=home('egon')
# print(res)

# print(home.__name__)
# print(home.__doc__)
help(home)
#方案八:在方案7的基礎上使用裝飾器的語法糖@符號讓裝飾器的使用變得簡潔
import time
from functools import wraps

def timmer(func):
    # func = index
    @wraps(func)
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res=func(*args,**kwargs)
        stop_time = time.time()
        print('run time is: %s' %(stop_time - start_time))
        return res
    return wrapper

@timmer  # index=timmer(index)
def index(x,y):
    time.sleep(1)
    print('index===>',x,y)

@timmer  # home=timmer(home)
def home(name):
    "home的文件註釋"
    time.sleep(0.5)
    print('welcome %s to home page' %name)
    return 123

res=index(1,2)
res=home('egon')

三、疊加多個裝飾器

四、有參裝飾器