你必须学写Python装饰器的五个理由

----装饰器能对你所写的代码产生极大的正面作用

Python装饰器是很容易使用的。任何一个会写Python函数的人都能够学会使用装饰器,比如下面这个:

@somedecorator

def some_function():

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

进群一起学习Python,欢迎各位大牛指教,小白求学。491308659邀请码(耀文)

但是,写出一个装饰器是一个完全不一样的技能。而且这也不是,你不得不理解下面这些:

闭包

如何将函数作为"第一类"参数来使用

变量参数

参数解包

甚至是Python是如何装载源码的一些细节

所有这些都需要花很多时间去理解和掌握。而且当你已经有这么一堆事情要学的时候,这些值得你花时间吗?

对我来说,这个问题的答案已然是“上千次的肯定,是的,我会学习!”同时这种偶然性也是会由你

写装饰器的最重要的好处是什么呢?在你每天的开发中,装饰器让你做什么做起来是很容易并且很强大的呢?

分析、日志以及指导

尤其是在大型软件中,我们通常需要专门来测试到底发生了什么,以及记录那些能量化不同行为的指标。通过在装饰器内部的函数或者方法里面封装这些重要的事件,这个装饰器能通俗易懂且容易地处理刚才这些所讲的需求。比如:

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!

同样的方式可以被用来计数或者其他指标。

验证与运行检查

Python的类型系统是相当类型化了的,但是也是很动态的。对于它的这些所有的好处,也意味着某一些bugs能够悄悄产生,而这些bugs能够在编译的时候被更类型化的语言(比如Java)所捕获。即使更长远看,你可能需要强化更复杂的,在数据进出的时候能个性化检查。装饰器能让你易于处理所有这些,并能一次性地应用它到很多函数上。

假设:你有一堆函数,每个函数都返回一个字典,这个字典包含一个称作“summary”的字段。这个字段的值不能超过80个字符长度;如果违反了,就是不对的。这里给出一个装饰器,当条件不满足的时候它能够抛出一个值错误(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):

# ...

创建框架

一旦你掌握了装饰器的编程,你将能够受益于使用装饰器的简单语法,而这让你增加语意给你的代码以便容易使用它。这就是下一个能够扩展Python自身语法的最好的工具。

实际中,很多流行的开源框架都在使用装饰器。网页应用框架Flask就使用了装饰器将URLs的路由交给那些处理HTTPS请求的函数。

# 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)

在这里,你有一个被叫做app的全局的对象,它有一个被称作route(路由)的方法并接受特定参数。这个路由方法返回一个被应用到处理函数的装饰器。在这个“面罩”下发生了一些很错综复杂的的事情,但是从Flask的使用者角度看,所有这些复杂性是完全被隐藏起来的了。

以这样的方式使用装饰器在stock Python中也有体现。举个例子,完全使用对象系统是有赖于@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()

这个类有3个不同的定义声明。但是,他们的语意是各不相同的。

1:constructor是一个正常方法

2:for_winter是一个类方法且提供一种类似于“车间”的东西

3:progess是只读、动态属性

对于日常来说,@classmethod和@property两个装饰器如此简单以致可以很容易扩展Python的对象语意

复用那些不可能复用的代码

Python提供给你一些很强大的工具用以封装代码为一个易用的形式,并带有充分的函数表示语法,支持函数式编程以及全面的对象系统。但是,装饰器也有它所不能捕获的某些形式的代码复用。

比如使用一个不可靠的API。你给那些通过HTTP对话的JSON发出一些请求的时候,API可以99.9%的时候工作正常。但是,有一小部分请求将使得服务器返回一个内部错误,然后你需要重试这些请求。在这个情况下,你将写一个重试逻辑,比如:

resp = None

while True:

resp = make_api_call()

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

tries += 1

continue

break

process_response(resp)

现在,假设你有十多个类似于make_api_call的函数,并且他们被所有代码调用。那么你是想要每次调用它们的时候写一个while循环呢?还是每次增加一个API调用函数的时候都把这段代码再写一遍?无论哪种选择都会产生大量的重复代码,除非你用装饰器。用了装饰器事情就简单了。

# 加了装饰器的函数会返回一个Response对象,

# 这个对象有个一二status_code的属性,

# 200表示成功;500表示服务器错误。

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():

# ....

进群一起学习Python,欢迎各位大牛指教,小白求学。491308659邀请码(耀文)

提升你的职业生涯

编写装饰器在一开始并不容易。它虽然不像火箭科学但是也需要你花很多努力去学习,去排除一些细微差异。很多开发者也从来不会通过这些麻烦而学习掌握装饰器编写。但是学习装饰器的确会给你优势。当你是你的团队里面学习如何写好装饰器的那个人的时候,并且你写的装饰器能解决一些实际问题的时候,其他开发者将会使用你的装饰器。因为,一旦这些装饰器编写的困难的部分被完成了,装饰器就会很容易使用。这就对你所写的代码产生极大的正面作用。这也会让你成为一个重要角色。

不论你如何编写装饰器,你会对下面你所要做的事情而感到兴奋,比如你即将能使用装饰器来做一些事情,以及装饰器是如何能永远改变你写Python代码的方式

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容