1. 程式人生 > >Python中的裝飾器的使用

Python中的裝飾器的使用

在說裝飾器之前先要理解一個概念,即《開放封閉原則》。


開放封閉原則(OCP,Open Closed Principle)是所有面向物件原則的核心。軟體設計本身所追求的目標就是封裝變化、降低耦合,而開放封閉原則正是對這一目標的最直接體現。其他的設計原則,很多時候是為實現這一目標服務的,例如以Liskov替換原則實現最佳的、正確的繼承層次,就能保證不會違反開放封閉原則。


寫程式碼要遵循《開放封閉原則》,簡單來說他規定已經實現的功能程式碼不允許被修改,但可以被擴充套件,即:
軟體實體應該是可擴充套件,而不可修改的。也就是說,對擴充套件是開放的,而對修改是封閉的。
因此,開放封閉原則主要體現在兩個方面:

  • 對擴充套件開放,意味著有新的需求或變化時,可以對現有程式碼進行擴充套件,以適應新的情況。
  • 對修改封閉,意味著類一旦設計完成,就可以獨立完成其工作,而不要對類進行任何修改。

案例一簡單應用(無參):
現有如下程式碼:
實現計算隨機數和的計算。

import random
def sum_1():
    sum_temp=0
    num=random.randint(1,99)
    for i in range(0,num):
        sum_temp=sum_temp+i
    print("計算1-%s的和"%(num-1))
    print(sum_temp)

if
__name__=="__main__": sum_1()

現新增需求點,要求計算該段程式碼的執行時間:
實現方式一:

import random,time
def sum_1():
    start_time=time.time()
    sum_temp=0
    num=random.randint(1,99)
    for i in range(0,num):
        sum_temp=sum_temp+i
    end_time=time.time()
    print("計算1-%s的和"%(num-1))
    print(sum_temp)
    print("程式執行時間:%s秒"
%((end_time-start_time)*1000)) if __name__=="__main__": sum_1() #執行結果: #計算1-48的和 #1176 #程式執行時間:1.0008811950683594秒

問題點:
1、違反《開放封閉原則》,已實現功能的程式碼不允許改動
2、如該段程式碼為核心業務支撐,供各子業務系統呼叫,如改動出現問題將影響所有相關業務系統的使用,風險較大。
實現方式二(使用裝飾器):

import random,time
def sum_1_deco(func):
    def wrapper():
        start_time=time.time()
        func()
        end_time=time.time()
        print("程式執行時間:%s秒"%((end_time-start_time)*1000))
    return wrapper #注意不加()  
@sum_1_deco  
def sum_1():
    sum_temp=0
    num=random.randint(1,99)
    for i in range(0,num):
        sum_temp=sum_temp+i
    print("計算1-%s的和"%(num-1))
    print(sum_temp)

if __name__=="__main__":
    sum_1()
#執行結果:
#計算1-73的和
#2701
#程式執行時間:0.5004405975341797秒

可以看到在以上程式碼中實現了相同的功能,但並未改動原有已實現功能的程式碼
案例二簡單應用(有參):
假設現有核心業務程式,該段程式用於在核心業務系統中獲取相關業務資料供各子業務系統進行呼叫,如下:

type_dict={ 1:'銷售資料',
            2:'財務資料',
            3:'客戶資料',
            }
def core(*args,**kwargs):
    print("使用者:%s 獲取資料:%s"%(kwargs['user'],type_dict[kwargs['data_type']])) 
if __name__=="__main__":
    core(data_type=1,user="admin")
#執行結果
#使用者:admin 獲取資料:銷售資料

該段程式碼承載核心業務資料,出於資訊保安考慮,資訊保安管理部門要求對呼叫該程式的各子業務系統進行安全驗證,僅有部分使用者可以呼叫。
實現方式一:

type_dict={ 1:'銷售資料',
            2:'財務資料',
            3:'客戶資料',
            }
# def core(*args,**kwargs):
#     print("使用者:%s 獲取資料:%s"%(kwargs['user'],type_dict[kwargs['data_type']])) 
user_list=["admin","admin1","admin2"]
def core(*args,**kwargs):
    if kwargs['user'] in user_list:
        print("使用者:%s 獲取資料:%s"%(kwargs['user'],type_dict[kwargs['data_type']])) 
    else:
        print("使用者:%s 許可權驗證失敗!!!"%kwargs['user'])


if __name__=="__main__":
    print("-"*50)
    core(data_type=1,user="admin")
    print("-"*50)
    core(data_type=2,user="user")
#執行結果
#--------------------------------------------------
#使用者:admin 獲取資料:銷售資料
#--------------------------------------------------
#使用者:user 許可權驗證失敗!!!

實現方式二(使用裝飾器):

type_dict={ 1:'銷售資料',
            2:'財務資料',
            3:'客戶資料',
            }

user_list=["admin","admin1","admin2"]
def core_deco(func):
    def wrapper(*args,**kwargs):
        if kwargs['user'] in user_list:
            func(*args,**kwargs)
        else:
            print("使用者:%s 許可權驗證失敗!!!"%kwargs['user'])
    return wrapper
@core_deco
def core(*args,**kwargs):
    print("使用者:%s 獲取資料:%s"%(kwargs['user'],type_dict[kwargs['data_type']])) 

if __name__=="__main__":
    print("-"*50)
    core(data_type=1,user="admin")
    print("-"*50)
    core(data_type=2,user="user")
#執行結果:
#--------------------------------------------------
#使用者:admin 獲取資料:銷售資料
#--------------------------------------------------
#使用者:user 許可權驗證失敗!!!

python裝飾器的執行時間:

  • 只要python直譯器執行到了這段程式碼那麼就會自動進行裝飾,而不是等到python呼叫該段程式碼時才進行裝飾