最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入了解python裝飾器

 更新時間:2022年03月02日 10:13:31   作者:xiaotanggao  
這篇文章主要介紹了解python裝飾器,裝飾器定義一個為其他函數添加功能的函數,裝飾器就是在不修改裝飾對象源代碼以及調用方式的前提下,為裝飾對象添加新功能,下面和小編一起進入文章內容了解更多知識,需要的朋友可以參考一下

一、裝飾器

1.相關知識點

  • *args:負責將多余的位置實參匯總,賦值給args
  • **kwargs:負責將多余的關鍵字實參匯總,賦值給kwargs

命名空間與作用域

函數對象:

  • 可以把函數當成參數傳入
  • 可以把函數當做返回值返回

函數的嵌套定義:在函數內定義函數

閉包函數:父函數的返回值為一個函數,被返回的函數調用了父函數的局部變量,且該函數可以在父函數外部執(zhí)行

裝飾器:

裝飾器:定義一個為其他函數添加功能的函數

為什么要使用裝飾器?

  • 開放封閉原則:開放擴展功能但封閉源代碼的修改
  • 裝飾器就是在不修改裝飾對象源代碼以及調用方式的前提下,為裝飾對象添加新功能

裝飾器實現:

需求:不修改源代碼,計算代碼執(zhí)行時間

 源代碼:

import time
def func0(x):
? ? time.sleep(1)
? ? print(x)
func0(0)

# 方案一:實現了計算代碼執(zhí)行時間的功能,但修改了源代碼,不符合要求
def func1(x):
? ? start = time.time()
? ? time.sleep(1)
? ? print(x)
? ? end = time.time()
? ? print('方案一 運行時間:{}'.format(end - start))
func1(1)

# 方案二:滿足要求,但代碼不具備重用性
start = time.time()
func0(2)
end = time.time()
print('方案二 運行時間:{}'.format(end - start))

# 方案三:將方案二封裝為函數,但修改了函數的調用方式,不符合要求
def wrapper():
? ? start = time.time()
? ? func0(3)
? ? end = time.time()
? ? print('方案三 運行時間:{}'.format(end - start))
wrapper()

# 方案四:不修改原函數的調用方式
def wrapper(x):
? ? start = time.time()
? ? func0(x)
? ? end = time.time()
? ? print('方案四 運行時間:{}'.format(end - start))
wrapper(4)

# 方案五:方案四參數被寫死,優(yōu)化方案四
def wrapper(*args, **kwargs):
? ? start = time.time()
? ? func0(*args, **kwargs)
? ? end = time.time()
? ? print('方案五 運行時間:{}'.format(end - start))
wrapper(5)

# 方案六:方案五函數被寫死,優(yōu)化方案五,但修改了源代碼的調用方式
def outter(a):
? ? def wrapper(*args, **kwargs):
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('方案六 運行時間:{}'.format(end - start))
? ? return wrapper
f = outter(func0)
f(6)

# 方案七:優(yōu)化方案六(outter即為裝飾器,用于裝飾func0)
def outter(a):
? ? def wrapper(*args, **kwargs):
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('方案七 運行時間:{}'.format(end - start))
? ? return wrapper
func0 = outter(func0)?? ?# 偷梁換柱,調用者無感知
func0(7)

運行結果:

0
1
方案一 運行時間:1.001857042312622
2
方案二 運行時間:1.0040733814239502
3
方案三 運行時間:1.0017154216766357
4
方案四 運行時間:1.007995367050171
5
方案五 運行時間:1.0145602226257324
6
方案六 運行時間:1.0046615600585938
7
方案七 運行時間:1.0094060897827148

2.語法糖

  • 使用語法糖,需要將裝飾器放到被裝飾對象前
# 不使用語法糖
import time
def func0(x):
? ? time.sleep(1)
? ? print(x)
# func0(0)

def outter(a):
? ? def wrapper(*args, **kwargs):
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('運行時間:{}'.format(end - start))
? ? return wrapper
func0 = outter(func0)
func0('hello')

# 使用語法糖
import time

def outter(a):
? ? def wrapper(*args, **kwargs):
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('運行時間:{}'.format(end - start))
? ? return wrapper

@outter # 語法糖,等價于該行func0 = outter(func0)
def func0(x):
? ? time.sleep(1)
? ? print(x)

func0('hello')
print(func0.__name__)?

運行結果:

hello
運行時間:1.0050427913665771
wrapper

3.裝飾器模板

?# 裝飾器模板
?def decorator_name(x):
? ? ?def wrapper(*args, **kwargs):
? ? ? ? ?# ...新添加的功能...
? ? ? ? ?# 下為調用原函數的格式
? ? ? ? ?x(*args, **kwargs)
? ? ?return wrapper

@decorator_name
?def func_name():
? ? ?pass

擴展:真正實現偷梁換柱,調用者無感知

  • 不使用裝飾器
?# 不使用裝飾器
import time


def func0(x):
? ? time.sleep(1)
? ? print(x)

func0('hello')
print(func0.__name__) # 查看函數名?
print(help(func0)) # 查看幫助信息(主要為注釋內容)

運行結果:

hello
func0
Help on function func0 in module main:

func0(x)
這是函數

None

使用裝飾器:

import time

def outter(a):
? ? def wrapper(*args, **kwargs):
? ? ? ? '''這是裝飾器'''
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('運行時間:{}'.format(end - start))
? ? return wrapper

@outter # func0 = outter(func0)
def func0(x):
? ? '''這是函數'''
? ? time.sleep(1)
? ? print(x)

func0('hello')
print(func0.__name__)
print(help(func0))

運行結果:

hello
運行時間:1.011878490447998
wrapper
Help on function wrapper in module main:

wrapper(*args, **kwargs)
這是裝飾器

None

嘔吼,露餡了

  • 解決方法,將原函數的屬性和方法,賦值給裝飾器內的wrapper
import time

def outter(a):
? ? def wrapper(*args, **kwargs):
? ? ? ? '''這是裝飾器'''
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('運行時間:{}'.format(end - start))
? ? wrapper.__name__ = a.__name__
? ? wrapper.__doc__ = a.__doc__
? ? return wrapper

@outter # func0 = outter(func0)
def func0(x):
? ? '''這是函數'''
? ? time.sleep(1)
? ? print(x)

func0('hello')
print(func0.__name__)
print(help(func0))

運行結果:

hello
運行時間:1.0030155181884766
func0
Help on function func0 in module main:

func0(*args, **kwargs)
這是函數

None

但是,函數有很多屬性和方法,一個一個手動修改過于麻煩,甚至可能會遺漏,但python也提供了解決方法

import time
from functools import wraps

def outter(a):
? ? @wraps(a)
? ? def wrapper(*args, **kwargs):
? ? ? ? '''這是裝飾器'''
? ? ? ? start = time.time()
? ? ? ? a(*args, **kwargs)
? ? ? ? end = time.time()
? ? ? ? print('運行時間:{}'.format(end - start))
? ? # wrapper.__name__ = a.__name__
? ? # wrapper.__doc__ = a.__doc__
? ? return wrapper

@outter # func0 = outter(func0)
def func0(x):
? ? '''這是函數'''
? ? time.sleep(1)
? ? print(x)

func0('hello')
print(func0.__name__)
print(help(func0))

運行結果:

hello
運行時間:1.0114128589630127
func0
Help on function func0 in module main:

func0(x)
這是函數

None

4.有參裝飾器

  • 裝飾器內需要傳入參數,但是由于語法糖的限制,裝飾器只能有一個參數,并且該參數僅用來接收被裝飾對象的內存地址,如何傳入其他參數?
  • 解決思路:將裝飾器做成閉包函數
def outter(db_type):
? ? # 裝飾器auth
? ? def auth(x):
? ? ? ? def wrapper(*args, **kwargs):
? ? ? ? ? ? if db_type == 'file':
? ? ? ? ? ? ? ? name = input('請輸入姓名:')
? ? ? ? ? ? ? ? passwd = input('請輸入密碼:')
? ? ? ? ? ? ? ? if name == 'zhangsan' and passwd == '123':
? ? ? ? ? ? ? ? ? ? x(*args, **kwargs)
? ? ? ? ? ? ? ? ? ? print('基于文件認證')
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? print('用戶名或密碼錯誤,認證失敗')
? ? ? ? ? ? elif db_type == 'mysql':
? ? ? ? ? ? ? ? x(*args, **kwargs)
? ? ? ? ? ? ? ? print('基于數據庫認證')
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? print('未知認證方式,不支持')
? ? ? ? return wrapper
? ? return auth

# 函數
auth = outter(db_type='file')
@auth
def file():
? ? print('hello')


auth = outter(db_type='mysql')
@auth
def mysql():
? ? print('world')

msg = input('請選擇認證方式(1=file|2=mysql):').strip()
if msg =='1':
? ? file()
elif msg == '2':
? ? mysql()
else:
? ? print('不支持')
  • 將傳入的參數寫入語法糖
def outter(db_type):
? ? # 裝飾器auth
? ? def auth(x):
? ? ? ? def wrapper(*args, **kwargs):
? ? ? ? ? ? if db_type == 'file':
? ? ? ? ? ? ? ? name = input('請輸入姓名:')
? ? ? ? ? ? ? ? passwd = input('請輸入密碼:')
? ? ? ? ? ? ? ? if name == 'zhangsan' and passwd == '123':
? ? ? ? ? ? ? ? ? ? x(*args, **kwargs)
? ? ? ? ? ? ? ? ? ? print('基于文件認證')
? ? ? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ? ? print('用戶名或密碼錯誤,認證失敗')
? ? ? ? ? ? elif db_type == 'mysql':
? ? ? ? ? ? ? ? x(*args, **kwargs)
? ? ? ? ? ? ? ? print('基于數據庫認證')
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? print('未知認證方式,不支持')
? ? ? ? return wrapper
? ? return auth

# 函數
# auth = outter(db_type='file')
# @auth
@outter(db_type='file')
def file():
? ? print('hello')

# auth = outter(db_type='mysql')
# @auth
@outter(db_type='mysql')
def mysql():
? ? print('world')

msg = input('請選擇認證方式(1=file|2=mysql):').strip()
if msg =='1':
? ? file()
elif msg == '2':
? ? mysql()
else:
? ? print('不支持')
  • 模板
# 有參裝飾器模板
def out_decorator_name(x,y,z):
? ? def decorator_name(a):
? ? ? ? def wrapper(*args, **kwargs):
? ? ? ? ? ? # ...新添加的功能...
? ? ? ? ? ? # 下為調用原函數的格式
? ? ? ? ? ? a(*args, **kwargs)
? ? ? ? return wrapper
? ? return decorator_name

@out_decorator_name(x,y,z=1)
def func_name():
? ? ?pass

到此這篇關于深入了解python裝飾器的文章就介紹到這了,更多相關python裝飾器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Python?ORM框架之SQLAlchemy?的基礎用法

    Python?ORM框架之SQLAlchemy?的基礎用法

    這篇文章主要介紹了Python?ORM框架之SQLAlchemy?的基礎用法,ORM全稱?Object?Relational?Mapping對象關系映射,更多詳細內容需要的小伙伴課題參考下面文章介紹。希望對你的學習有所幫助
    2022-03-03
  • python實現自動搶課腳本的示例代碼

    python實現自動搶課腳本的示例代碼

    本文主要介紹了python實現自動搶課腳本的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • python算法測試結果自動保存到excel表格的實現步驟

    python算法測試結果自動保存到excel表格的實現步驟

    我們在進行算法評估是通常會針對每個樣本的算法處理結果進行統(tǒng)計,例如每個樣本正確預測數量、漏檢數量和誤檢數量、精度等,本文小編將給大家介紹python算法測試結果自動保存到excel表格的實現步驟,感興趣的朋友可以參考下
    2023-12-12
  • Python使用PyYAML庫讀寫yaml文件的方法

    Python使用PyYAML庫讀寫yaml文件的方法

    這篇文章主要介紹了Python使用PyYAML庫讀寫yaml文件的方法,包括YAML基本概念介紹及YAML語法知識,結合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • PyCharm在win10的64位系統(tǒng)安裝實例

    PyCharm在win10的64位系統(tǒng)安裝實例

    給大家介紹一下在win10的64位系統(tǒng)中安裝PyCharm的操作過程以及需要注意的地方。
    2017-11-11
  • python八種降維方法匯總

    python八種降維方法匯總

    在Python中,有多種降維方法可以使用,本文就來介紹八種降維方法以及使用場景,具有一定的參考價值,感興趣的可以一下,感興趣的可以了解一下
    2023-10-10
  • 在Python程序中操作文件之isatty()方法的使用教程

    在Python程序中操作文件之isatty()方法的使用教程

    這篇文章主要介紹了在Python程序中操作文件之isatty()方法的使用教程,是Python入門學習中的基礎知識,需要的朋友可以參考下
    2015-05-05
  • python3+opencv3識別圖片中的物體并截取的方法

    python3+opencv3識別圖片中的物體并截取的方法

    今天小編就為大家分享一篇python3+opencv3識別圖片中的物體并截取的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • python目標檢測yolo3詳解預測及代碼復現

    python目標檢測yolo3詳解預測及代碼復現

    這篇文章主要為大家介紹了python目標檢測yolo3詳解預測及代碼復現,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 實踐Python的爬蟲框架Scrapy來抓取豆瓣電影TOP250

    實踐Python的爬蟲框架Scrapy來抓取豆瓣電影TOP250

    這篇文章主要介紹了實踐Python的爬蟲框架Scrapy來抓取豆瓣電影TOP250的過程,文中的環(huán)境基于Windows操作系統(tǒng),需要的朋友可以參考下
    2016-01-01

最新評論

东台市| 宜川县| 佛坪县| 天门市| 额敏县| 曲靖市| 五大连池市| 临武县| 日照市| 榆树市| 平邑县| 攀枝花市| 京山县| 霍州市| 乾安县| 仙居县| 中方县| 方山县| 新巴尔虎右旗| 余江县| 武威市| 霸州市| 灵璧县| 武汉市| 兴义市| 瑞丽市| 东源县| 昌宁县| 高密市| 会理县| 庆云县| 五原县| 黔东| 锡林浩特市| 海城市| 通辽市| 和静县| 万盛区| 齐河县| 无极县| 双峰县|