其实早就想写一篇深入浅出装饰器的文章,苦于一直没有找到很好的例子描述,自己除了在写api参数检测和日志打印的时候用到以外,其他地方也没有什么重度使用所以一直没有写。

我不会讲解装饰器的理论,还有各种基础原理什么的。网上多得不行的资料 千篇一律,这里只总结怎么使用,和记住装饰器。

这次我会以假装使用一个写好的 星港(starport)和指挥中心(commander center)去建造单位,来阐述和讲解装饰器 let's go

在starport.py下我们使用它生产viking:

import time
from tqdm import tqdm
from building.starport import starport_ready
from building.command_center import commander_center_ready @starport_ready()
def produce_a_viking(seconds=30):
for i in tqdm(xrange(seconds)):
time.sleep(1)

可以看到生产viking的函数很简单 花费30秒时间去生产一架战机,但是做这件事情之前,我们应该有一个需求是,有必要去检查starport是否有在使用,如果ready我们就打印ready的日志然后直接开始生产viking,但是我们也有可能因为之前在研究 隐形科技(cloak)而且还没有完成,那么我们可能需要等待cloak研究完成之后才能生产viking。

所以我在写starport_ready这个装饰器 有两个需求:

1. 如果starport_ready 那么我就打印日志,然后开始生产,生产结束后继续打印日志。

2. 如果前面有东西在研究,也就是我给starport_ready装饰器传参,然后会先研究前面的科技,再开始生产。

下面来看装饰器代码:

# coding: utf-8
import time
from tqdm import tqdm
from functools import wraps
from starcraft2.building import logger def starport_upgrade(SCUpgrade):
logger.info("starport upgrade: {0}".format(SCUpgrade)) if SCUpgrade == "High Capacity Fuel Tanks":
for i in tqdm(xrange(57)):
time.sleep(1)
elif SCUpgrade == "Explosive Shrapnel Shells":
for i in tqdm(xrange(79)):
time.sleep(1)
elif SCUpgrade == "Corvid Reactor":
for i in tqdm(xrange(79)):
time.sleep(1)
elif SCUpgrade == "Banshee Cloaking Field":
for i in tqdm(xrange(79)):
time.sleep(1)
elif SCUpgrade == "Hyperflight Rotors":
for i in tqdm(xrange(96)):
time.sleep(1)
elif SCUpgrade == "Advanced Ballistics":
for i in tqdm(xrange(79)):
time.sleep(1) logger.info("starport upgrade complete: {0}".format(SCUpgrade)) def starport_ready(SCUpgrade=None): def starport_decrator(produce_unit):
@wraps(produce_unit)
def _(*args, **kwargs):
try:
if SCUpgrade:
starport_upgrade(SCUpgrade)
logger.info("starport ready") logger.info("star produce: {}".format(produce_unit.__name__[10:]))
produce_unit(*args, **kwargs)
logger.info("produce complete: {}".format(produce_unit.__name__[10:]))
except Exception as e:
logger.error(e.message)
return _ return starport_decrator

这里我直接上了装饰器传参的例子,如果装饰器里面传递过来有SCUpgrade参数,例如研究cloak科技,那么会在函数里面先研究了该科技之后starport才会ready。

在仔细讲解这个装饰器之前,还是先来说说 functool里面的wrap工具。其实它本身也是一个装饰器,由于我们在装饰器内部返回的是函数,直接这样操作我们会改变被包装函数的.__name__属性,导致我们运行的函数认为不是自己运行的,而是被包裹的函数运行的。举个例子,本来这个函数我们认为

produce_a_viking

的.__name__应该是自己才对。但是如果没有@wrap的包裹,会变成 _。 所以使用functool里面的@wrap将相关模仿方法和属性都拷贝过去。这也是为什么使用@wrap的原因。

讲完了wrap现在开始说一下这个装饰器:

starport_ready

1. 接受一个研究科技的参数,如果这个参数没有则默认为None

def starport_decrator(produce_unit):

2. 这里接受装饰的函数作为参数

@wraps(produce_unit)

3. 使用wrap将使用装饰器函数里面的方法拷贝出来最后用来赋值给包装的函数,就是上面说的类似于__name__方法的覆盖。

def _(*args, **kwargs):
try:
if SCUpgrade:
starport_upgrade(SCUpgrade)
logger.info("starport ready") logger.info("star produce: {}".format(produce_unit.__name__[10:]))
produce_unit(*args, **kwargs)
logger.info("produce complete: {}".format(produce_unit.__name__[10:]))
except Exception as e:
logger.error(e.message)

4. 主包装运行的函数,首先判断是否有要研究的科技,没有则在日志里面记录一跳starport ready 。这个时候开始生产传递进来的要生产的单位,开始运行生产单位的函数。也就是实用装饰器的函数,运行完了之后再在日志里面记一条完成生产。

总结:

装饰器其实蛮简单的,主要是一些用的地方,能不能将其用在合适的地方,是能否让python代码看起来更pythonic的关键。

在不需要使用装饰器的时候不要因为炫技而使用,这样可能会让代码看起来不清晰,从而变得更加复杂难以维护。

Reference:

https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/  python进阶decorator部分

python 深入浅出装饰器(decorator)--举的例子关于星级争霸2(starcraft2)的更多相关文章

  1. python函数编程-装饰器decorator

    函数是个对象,并且可以赋值给一个变量,通过变量也能调用该函数: >>> def now(): ... print('2017-12-28') ... >>> l = ...

  2. 详解python的装饰器decorator

    装饰器本质上是一个python函数,它可以让其它函数在不需要任何代码改动的情况下增加额外的功能. 装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志,性能测试,事务处理,缓存, ...

  3. 关于Python的装饰器 decorator

    装饰器的原理:其实就是高阶函数,接收原函数以在之前之后进行操作. 语法格式是固定的:先定义一个函数,再使用@语法调用该函数. 例子一: import functools # 定义装饰器,固定格式 de ...

  4. Python学习——装饰器/decorator/语法糖

    装饰器 定义:本质是函数,为其他函数添加附加的功能. 原则:1.不能修改原函数的源代码 2.不能修改被原函数的调用方式 重点理解: 1.函数即“变量” 2.高阶函数:返回值中包含函数名 3.嵌套函数 ...

  5. 关于python的装饰器(初解)

    在python中,装饰器(decorator)是一个主要的函数,在工作中,有了装饰器简直如虎添翼,许多公司面试题也会考装饰器,而装饰器的意思又很难让人理解. python中,装饰器是一个帮函数动态增加 ...

  6. Python之装饰器、迭代器和生成器

    在学习python的时候,三大“名器”对没有其他语言编程经验的人来说,应该算是一个小难点,本次博客就博主自己对装饰器.迭代器和生成器理解进行解释. 为什么要使用装饰器 什么是装饰器?“装饰”从字面意思 ...

  7. python 装饰器(decorator)

    装饰器(decorator) 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 装饰器(decorator)是一种高级Python语 ...

  8. python 语法之 装饰器decorator

    装饰器 decorator 或者称为包装器,是对函数的一种包装. 它能使函数的功能得到扩充,而同时不用修改函数本身的代码. 它能够增加函数执行前.执行后的行为,而不需对调用函数的代码做任何改变. 下面 ...

  9. python之装饰器(decorator)

    python的装饰器如果用得好,那是大神,用的不好最好别用... 装饰器(decorator)主要包含俩大属性: 1.不能改变原有函数的调用方式 2.不能改变原有函数的代码 第一个表示,我不需要改变原 ...

随机推荐

  1. Java相关框架资料及其基础资料、进阶资料、测试资料之分享

    个人说明:只为分享,不为其他,愿所有的程序员们在编程的世界自由翱翔吧! 在我看来,只有不断实战,不断学习,不断积累,不断归纳总结,形成自己的核心竞争力,方能在未来竞争中脱颖而出! 程序员谨记!重要的事 ...

  2. Python import用法

    官方文档说明: Python code in one module gains access to the code in another module by the process of impor ...

  3. vue2.0中使用sass

    第一部分:Sass语言 Sass是一种强大的css扩展语言(css本身并不是一门语言),它允许你使用变量.嵌套规则.mixins.导入等css没有但开发语言(如Java.C#.Ruby等)有的一些特性 ...

  4. 【php增删改查实例】第十三节 - EasyUI列格式化

    因为easyUI的datagrid组件是横着一格一格加载数据的,一行加载好了之后才会去加载下一行.所谓的列格式化,就是在加载某一列的所有单元格时,对即将加载到这些单元格的数据进行二次包装. 比如,我们 ...

  5. 【强化学习】python 实现 q-learning 例五(GUI)

    本文作者:hhh5460 本文地址:https://www.cnblogs.com/hhh5460/p/10143579.html 感谢pengdali,本文的 class Maze 参考了他的博客, ...

  6. InnoDB 文件系统

    1. 操作系统文件系统inode 2. InnoDB的存储结构 2.1Innodb inode page 参考 http://mysql.taobao.org/monthly/2016/02/01/ ...

  7. Spring+SpringMVC+MyBatis+easyUI整合进阶篇(八)线上Mysql数据库崩溃事故的原因和处理

    前文提要 承接前文<一次线上Mysql数据库崩溃事故的记录>,在文章中讲到了一次线上数据库崩溃的事件记录,建议两篇文章结合在一起看,不至于摸不着头脑. 由于时间原因,其中只讲了当时的一些经 ...

  8. js类型----你所不知道的JavaScript系列(5)

    ECMAScirpt 变量有两种不同的数据类型:基本类型,引用类型.也有其他的叫法,比如原始类型和对象类型等. 1.内置类型 JavaScript 有七种内置类型: • 空值(null) • 未定义( ...

  9. ExtJS框架基础:事件模型及其常用功能

    前言 工作中用ExtJS有一段时间了,Ext丰富的UI组件大大的提高了开发B/S应用的效率.虽然近期工作中天天都用到ExtJS,但很少对ExtJS框架原理性的东西进行过深入学习,这两天花了些时间学习了 ...

  10. Webpack 2 视频教程 007 - 配置 WDS 进行浏览器自动刷新

    原文发表于我的技术博客 这是我免费发布的高质量超清「Webpack 2 视频教程」. Webpack 作为目前前端开发必备的框架,Webpack 发布了 2.0 版本,此视频就是基于 2.0 的版本讲 ...