你必須學(xué)寫(xiě)Python裝飾器的五個(gè)理由

----裝飾器能對(duì)你所寫(xiě)的代碼產(chǎn)生極大的正面作用

Python裝飾器是很容易使用的。任何一個(gè)會(huì)寫(xiě)Python函數(shù)的人都能夠?qū)W會(huì)使用裝飾器,比如下面這個(gè):

@somedecorator

def some_function():

print("Check it out, I"m using decorators!")

進(jìn)群一起學(xué)習(xí)Python,歡迎各位大牛指教,小白求學(xué)。491308659邀請(qǐng)碼(耀文)

但是,寫(xiě)出一個(gè)裝飾器是一個(gè)完全不一樣的技能。而且這也不是,你不得不理解下面這些:

閉包

如何將函數(shù)作為"第一類"參數(shù)來(lái)使用

變量參數(shù)

參數(shù)解包

甚至是Python是如何裝載源碼的一些細(xì)節(jié)

所有這些都需要花很多時(shí)間去理解和掌握。而且當(dāng)你已經(jīng)有這么一堆事情要學(xué)的時(shí)候,這些值得你花時(shí)間嗎?

對(duì)我來(lái)說(shuō),這個(gè)問(wèn)題的答案已然是“上千次的肯定,是的,我會(huì)學(xué)習(xí)!”同時(shí)這種偶然性也是會(huì)由你

寫(xiě)裝飾器的最重要的好處是什么呢?在你每天的開(kāi)發(fā)中,裝飾器讓你做什么做起來(lái)是很容易并且很強(qiáng)大的呢?

分析、日志以及指導(dǎo)

尤其是在大型軟件中,我們通常需要專門(mén)來(lái)測(cè)試到底發(fā)生了什么,以及記錄那些能量化不同行為的指標(biāo)。通過(guò)在裝飾器內(nèi)部的函數(shù)或者方法里面封裝這些重要的事件,這個(gè)裝飾器能通俗易懂且容易地處理剛才這些所講的需求。比如:

from myapp.log import logger

def log_order_event(func):

def wrapper(*args, **kwargs):

logger.info("Ordering: %s", func.__name__)

order = func(*args, **kwargs)

logger.debug("Order result: %s", order.result)

return order

return wrapper

@log_order_event

def order_pizza(*toppings):

# let"s get some pizza!

同樣的方式可以被用來(lái)計(jì)數(shù)或者其他指標(biāo)。

驗(yàn)證與運(yùn)行檢查

Python的類型系統(tǒng)是相當(dāng)類型化了的,但是也是很動(dòng)態(tài)的。對(duì)于它的這些所有的好處,也意味著某一些bugs能夠悄悄產(chǎn)生,而這些bugs能夠在編譯的時(shí)候被更類型化的語(yǔ)言(比如Java)所捕獲。即使更長(zhǎng)遠(yuǎn)看,你可能需要強(qiáng)化更復(fù)雜的,在數(shù)據(jù)進(jìn)出的時(shí)候能個(gè)性化檢查。裝飾器能讓你易于處理所有這些,并能一次性地應(yīng)用它到很多函數(shù)上。

假設(shè):你有一堆函數(shù),每個(gè)函數(shù)都返回一個(gè)字典,這個(gè)字典包含一個(gè)稱作“summary”的字段。這個(gè)字段的值不能超過(guò)80個(gè)字符長(zhǎng)度;如果違反了,就是不對(duì)的。這里給出一個(gè)裝飾器,當(dāng)條件不滿足的時(shí)候它能夠拋出一個(gè)值錯(cuò)誤(ValueError),如下。

def validate_summary(func):

def wrapper(*args, **kwargs):

data = func(*args, **kwargs)

if len(data["summary"]) > 80:

raise ValueError("Summary too long")

return data

return wrapper

@validate_summary

def fetch_customer_data():

# ...

@validate_summary

def query_orders(criteria):

# ...

@validate_summary

def create_invoice(params):

# ...

創(chuàng)建框架

一旦你掌握了裝飾器的編程,你將能夠受益于使用裝飾器的簡(jiǎn)單語(yǔ)法,而這讓你增加語(yǔ)意給你的代碼以便容易使用它。這就是下一個(gè)能夠擴(kuò)展Python自身語(yǔ)法的最好的工具。

實(shí)際中,很多流行的開(kāi)源框架都在使用裝飾器。網(wǎng)頁(yè)應(yīng)用框架Flask就使用了裝飾器將URLs的路由交給那些處理HTTPS請(qǐng)求的函數(shù)。

# For a RESTful todo-list API.

@app.route("/tasks/", methods=["GET"])

def get_all_tasks():

tasks = app.store.get_all_tasks()

return make_response(json.dumps(tasks), 200)

@app.route("/tasks/", methods=["POST"])

def create_task():

payload = request.get_json(force=True)

task_id = app.store.create_task(

summary = payload["summary"],

description = payload["description"],

)

task_info = {"id": task_id}

return make_response(json.dumps(task_info), 201)

@app.route("/tasks//")

def task_details(task_id):

task_info = app.store.task_details(task_id)

if task_info is None:

return make_response("", 404)

return json.dumps(task_info)

在這里,你有一個(gè)被叫做app的全局的對(duì)象,它有一個(gè)被稱作route(路由)的方法并接受特定參數(shù)。這個(gè)路由方法返回一個(gè)被應(yīng)用到處理函數(shù)的裝飾器。在這個(gè)“面罩”下發(fā)生了一些很錯(cuò)綜復(fù)雜的的事情,但是從Flask的使用者角度看,所有這些復(fù)雜性是完全被隱藏起來(lái)的了。

以這樣的方式使用裝飾器在stock Python中也有體現(xiàn)。舉個(gè)例子,完全使用對(duì)象系統(tǒng)是有賴于@classmethod和@property裝飾器的:

class WeatherSimulation:

def __init__(self, **params):

self.params = params

@classmethod

def for_winter(cls, **other_params):

params = {"month": "Jan", "temp": "0"}

params.update(other_params)

return cls(**params)

@property

def progress(self):

return self.completed_iterations() / self.total_iterations()

這個(gè)類有3個(gè)不同的定義聲明。但是,他們的語(yǔ)意是各不相同的。

1:constructor是一個(gè)正常方法

2:for_winter是一個(gè)類方法且提供一種類似于“車間”的東西

3:progess是只讀、動(dòng)態(tài)屬性

對(duì)于日常來(lái)說(shuō),@classmethod和@property兩個(gè)裝飾器如此簡(jiǎn)單以致可以很容易擴(kuò)展Python的對(duì)象語(yǔ)意

復(fù)用那些不可能復(fù)用的代碼

Python提供給你一些很強(qiáng)大的工具用以封裝代碼為一個(gè)易用的形式,并帶有充分的函數(shù)表示語(yǔ)法,支持函數(shù)式編程以及全面的對(duì)象系統(tǒng)。但是,裝飾器也有它所不能捕獲的某些形式的代碼復(fù)用。

比如使用一個(gè)不可靠的API。你給那些通過(guò)HTTP對(duì)話的JSON發(fā)出一些請(qǐng)求的時(shí)候,API可以99.9%的時(shí)候工作正常。但是,有一小部分請(qǐng)求將使得服務(wù)器返回一個(gè)內(nèi)部錯(cuò)誤,然后你需要重試這些請(qǐng)求。在這個(gè)情況下,你將寫(xiě)一個(gè)重試邏輯,比如:

resp = None

while True:

resp = make_api_call()

if resp.status_code == 500 and tries < MAX_TRIES:

tries += 1

continue

break

process_response(resp)

現(xiàn)在,假設(shè)你有十多個(gè)類似于make_api_call的函數(shù),并且他們被所有代碼調(diào)用。那么你是想要每次調(diào)用它們的時(shí)候?qū)懸粋€(gè)while循環(huán)呢?還是每次增加一個(gè)API調(diào)用函數(shù)的時(shí)候都把這段代碼再寫(xiě)一遍?無(wú)論哪種選擇都會(huì)產(chǎn)生大量的重復(fù)代碼,除非你用裝飾器。用了裝飾器事情就簡(jiǎn)單了。

# 加了裝飾器的函數(shù)會(huì)返回一個(gè)Response對(duì)象,

# 這個(gè)對(duì)象有個(gè)一二status_code的屬性,

# 200表示成功;500表示服務(wù)器錯(cuò)誤。

def retry(func):

def retried_func(*args, **kwargs):

MAX_TRIES = 3

tries = 0

while True:

resp = func(*args, **kwargs)

if resp.status_code == 500 and tries < MAX_TRIES:

tries += 1

continue

break

return resp

return retried_func

上述例子可以讓你方便使用裝飾器@retry

@retry

def make_api_call():

# ....

進(jìn)群一起學(xué)習(xí)Python,歡迎各位大牛指教,小白求學(xué)。491308659邀請(qǐng)碼(耀文)

提升你的職業(yè)生涯

編寫(xiě)裝飾器在一開(kāi)始并不容易。它雖然不像火箭科學(xué)但是也需要你花很多努力去學(xué)習(xí),去排除一些細(xì)微差異。很多開(kāi)發(fā)者也從來(lái)不會(huì)通過(guò)這些麻煩而學(xué)習(xí)掌握裝飾器編寫(xiě)。但是學(xué)習(xí)裝飾器的確會(huì)給你優(yōu)勢(shì)。當(dāng)你是你的團(tuán)隊(duì)里面學(xué)習(xí)如何寫(xiě)好裝飾器的那個(gè)人的時(shí)候,并且你寫(xiě)的裝飾器能解決一些實(shí)際問(wèn)題的時(shí)候,其他開(kāi)發(fā)者將會(huì)使用你的裝飾器。因?yàn)椋坏┻@些裝飾器編寫(xiě)的困難的部分被完成了,裝飾器就會(huì)很容易使用。這就對(duì)你所寫(xiě)的代碼產(chǎn)生極大的正面作用。這也會(huì)讓你成為一個(gè)重要角色。

不論你如何編寫(xiě)裝飾器,你會(huì)對(duì)下面你所要做的事情而感到興奮,比如你即將能使用裝飾器來(lái)做一些事情,以及裝飾器是如何能永遠(yuǎn)改變你寫(xiě)Python代碼的方式

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 每個(gè)人都有的內(nèi)褲主要功能是用來(lái)遮羞,但是到了冬天它沒(méi)法為我們防風(fēng)御寒,咋辦?我們想到的一個(gè)辦法就是把內(nèi)褲改造一下,...
    chen_000閱讀 1,404評(píng)論 0 3
  • Python裝飾器的高級(jí)用法(翻譯) 原文地址https://www.codementor.io/python/t...
    城南道閱讀 4,875評(píng)論 1 22
  • 上證指數(shù)3402.52-0.79% 深證指數(shù)11462.11-1.04% 中小板指7893.46-2.06% 創(chuàng)業(yè)...
    百股精看盤(pán)閱讀 373評(píng)論 0 0
  • 前幾天看到在英國(guó)最火爆的早間新聞節(jié)目中接受采訪的機(jī)器人索菲亞,她對(duì)主持人的提問(wèn)回答得幽默機(jī)智,并能談笑風(fēng)生,讓人稱...
    田真十閱讀 395評(píng)論 2 3

友情鏈接更多精彩內(nèi)容