網站首頁 編程語言 正文
裝飾器的價值不言而喻,可以用來增強函數功能、簡化代碼、減少代碼冗余。
它的使用場景同樣很多,比較簡單的場景包含打印日志、統計運行時間,這類例子和用法網上已經很多了:
def time_dec(func):
?
def wrapper(*arg):
t = time.clock()
res = func(*arg)
print func.func_name, time.clock()-t
return res
?
return wrapper
?
?
@time_dec
def myFunction(n):
...
再進階一些的,可以用來校驗函數傳入參數類型、線程同步、單元測試等:
@parameters(
(2, 4, 6),
(5, 6, 11),
)
def test_add(a, b, expected):
assert a + b == expected
目前可以用的裝飾器可以分為如下幾類:
- 自定義
- 第三方工具包
- 內置
下面就分別來介紹一下。
自定義
關于自定義的裝飾器在前面已經提到了,我在開發過程中經常用到的就是日志打印、計時、數據校驗等場景,通過裝飾器可以提高代碼的簡潔性,避免重復造輪子。
除了這些基本的,也有一些比較實用的地方。
作為開發同學,肯定會遇到不同的運行環境:
- 開發環境
- 測試環境
- 生產環境
有時候,我們期望一個函數在不同環境下執行不同的過程,產出不同的結果,做一些環境的隔離和差異化處理。
通過裝飾器就可以很好的解決:
production_servers = [...]
?
def production(func: Callable):
def inner(*args, **kwargs):
if gethostname() in production_servers:
return func(*args, **kwargs)
else:
print('This host is not a production server, skipping function decorated with @production...')
return inner
?
def development(func: Callable):
def inner(*args, **kwargs):
if gethostname() not in production_servers:
return func(*args, **kwargs)
else:
print('This host is a production server, skipping function decorated with @development...')
return inner
?
def sit(func: Callable):
def inner(*args, **kwargs):
print('Skipping function decorated with @sit...')
return inner
?
@production
def foo():
print('Running in production, touching databases!')
?
foo()
?
@development
def foo():
print('Running in production, touching databases!')
?
foo()
?
@inactive
def foo():
print('Running in production, touching databases!')
?
foo()
簡單的介紹一下這段代碼。
在這里,先是羅列了生產環境的服務列表,然后分別定義了生產、開發、測試環境的裝飾器,然后給同名的函數就可以配上對應的裝飾器。
在執行代碼的過程中,這段代碼會首先獲取hostname,自動判斷所在環境,然后執行對應函數。
第三方工具包
上面是根據我們在開發過程中遇到的個性化場景進行來自定義一個裝飾器。
作為一款以工具包著稱的編程語言,Python中也有很多工具包提供了一些實用的裝飾器。
以日志為例,這是每個程序員都無法繞開的。
調試程序對于大多數開發者來說是一項必不可少的工作,當我們想要知道代碼是否按照預期的效果在執行時,我們會想到去輸出一下局部變量與預期的進行比對。目前大多數采用的方法主要有以下幾種:
- Print函數
- Log日志
- IDE調試器
但是這些方法有著無法忽視的弱點:
- 繁瑣
- 過度依賴工具
其中有一款不錯的開源工具PySnooper就通過裝飾器把這個問題巧妙的解決了。
PySnooper的調用方式就是通過@pysnooper.snoop的方式進行使用,該裝飾器可以傳入一些參數來實現一些目的,具體如下:
參數描述:
- None輸出日志到控制臺
- filePath輸出到日志文件,例如'log/file.log'
- prefix給調試的行加前綴,便于識別
- watch查看一些非局部變量表達式的值
- watch_explode展開值用以查看列表/字典的所有屬性或項
- depth顯示函數調用的函數的snoop行
舉個例子:
import numpy as np
import pysnooper
?
@pysnooper.snoop()
def one(number):
mat = []
while number:
mat.append(np.random.normal(0, 1))
number -= 1
return mat
?
one(3)
然后,就會給出如下輸出:
Starting var:.. number = 3
22:17:10.634566 call ? ? ? ? 6 def one(number):
22:17:10.634566 line ? ? ? ? 7 ? ? mat = []
New var:....... mat = []
22:17:10.634566 line ? ? ? ? 8 ? ? while number:
22:17:10.634566 line ? ? ? ? 9 ? ? ? ? mat.append(np.random.normal(0, 1))
Modified var:.. mat = [-0.4142847169210746]
22:17:10.634566 line ? ? ? ?10 ? ? ? ? number -= 1
Modified var:.. number = 2
22:17:10.634566 line ? ? ? ? 8 ? ? while number:
22:17:10.634566 line ? ? ? ? 9 ? ? ? ? mat.append(np.random.normal(0, 1))
Modified var:.. mat = [-0.4142847169210746, -0.479901983375219]
22:17:10.634566 line ? ? ? ?10 ? ? ? ? number -= 1
Modified var:.. number = 1
22:17:10.634566 line ? ? ? ? 8 ? ? while number:
22:17:10.634566 line ? ? ? ? 9 ? ? ? ? mat.append(np.random.normal(0, 1))
Modified var:.. mat = [-0.4142847169210746, -0.479901983375219, 1.0491540468063252]
22:17:10.634566 line ? ? ? ?10 ? ? ? ? number -= 1
Modified var:.. number = 0
22:17:10.634566 line ? ? ? ? 8 ? ? while number:
22:17:10.634566 line ? ? ? ?11 ? ? return mat
22:17:10.634566 return ? ? ?11 ? ? return mat
Return value:.. [-0.4142847169210746, -0.479901983375219, 1.0491540468063252]
局部變量值、代碼片段、局部變量所在行號、返回結果等,這些關鍵信息都輸出了,既方便,又清晰。
內置
除了自定義和第三方工具包之外,Python還內置了很多不錯的裝飾器,例如@abc.abstractmethod、@asyncio.coroutine、@classmethod等等。
這里著重提一個非常強大的裝飾器,能夠極大的提升Python的運行速度和效率,通過一個裝飾器能夠將Python代碼的執行速度提升上萬倍,這個裝飾器就是@functools.lru_cache。
以比較知名的斐波那契數列的例子來演示一下。
由于它遞歸計算的過程中,還會用到之前計算的結果,因此會涉及較多的重復計算,下面先看一下正常計算的耗時情況。
import time as tt
?
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
?
t1 = tt.time()
fib(30)
print("Time taken: {}".format(tt.time() - t1))
# 0.2073
n等于30時,耗時0.2073。
加上@functools.lru_cache裝飾器再看一下:
import time as tt
import functools
?
@functools.lru_cache(maxsize=5)
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
?
t1 = tt.time()
fib(30)
print("Time taken: {}".format(tt.time() - t1))
# 1.811981e-05
耗時為1.811981e-05,足足差了4個量級,快了10000+倍!
原文鏈接:https://blog.csdn.net/weixin_56659172/article/details/125658212
相關推薦
- 2022-08-01 Android?WebView軟鍵盤遮擋輸入框方案詳解_Android
- 2022-05-29 ASP.NET?Core在WebApi項目中使用Cookie_實用技巧
- 2022-07-26 討論nginx?location?順序問題_nginx
- 2023-01-28 python中使用redis用法詳解_Redis
- 2022-10-31 Kotlin中Object關鍵字的使用示例介紹_Android
- 2022-03-27 C語言中scanf與scnaf_s函數詳解_C 語言
- 2021-12-18 Nginx下SSL證書安裝部署步驟介紹_nginx
- 2022-10-29 subplots_adjust()函數--matplotlib
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支