众所周知,Python本身有很多优雅的语法,让你能用一行代码写出其他语言很多行代码才能做的事情,比如:

最常用的迭代(eg: for i in range(1,10)), 列表生成式(eg: [ x*x for x in range(1,10) if x % 2 ==  0])

map()能让你把函数作用于多个元素, reduce()能让你把多个元素的结果按照你预想的方式组合在一起,filter()能让你快速筛选出复合条件的数据

以上具体用法可以参考https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317793224211f408912d9c04f2eac4d2af0d5d3d7b2000

而我们这次要讨论的装饰器decorator,可以在不改变现有函数的前提下更有效率的重用代码

比如我们在实际工作当中,经常需要添加try...except来捕获异常,但是一个个加也太麻烦了,此时我们就可以用decorator装饰器来实现

比如我们有以下原始函数

def hello():
print("Hello, world!") def bye():
print("Bye, world!")

正常情况下,如果都需要捕获异常的话,需要加两次try...except来做:

def main():
try:
hello()
except Exception as e:
print('except:', e)
....
....
try:
bye()
except Exception as e:
print('except:', e)
....
....

但是当我们有装饰器decorator的时候,一切都会变得特别优雅而简单,首先定义好我们的装饰器:

import functools

def decorator_try(func):
@functools.wraps(func)
def wrapper(*arg,**kw):
try:
func(*arg, **kw)
except Exception as e:
print('except:', e)
return wrapper

然后只需要在原来的hello()和bye()函数定义之前添加一行语法就可以:

@decorator_try
def hello():
print("Hello, world!") @decorator_try
def bye():
print("Bye, world!")

然后执行的时候任何东西都不用加

def main():
hello()
....
....
bye()

结果为:

>>> hello()
Hello, world!
>>> hello(1,2)
except: hello() takes 0 positional arguments but 2 were given

具体的关于decorator装饰器的语法解释可以参考https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000

另外要注意装饰器定义中 func(*arg, **kw) 和 return wrapper的区别,注意看一个是带参数,一个不带参数与括号,带参数表示执行这个函数,不带参数和括号代表把定义的函数作为一个参数传递了过去,这对理解decorator的语法是至关重要的。因为:

@decorator_try放到hello()函数的定义前,相当于执行了语句:

hello = decorator_try(hello)

如果想更深入的了解decorator装饰器,推荐一篇博文https://www.cnblogs.com/zh605929205/p/7704902.html

下面再写一个例子:

比如我们有一个函数,下载图片,用装饰器实现timeout之后,自动重新下载一次。

import functools
import random # 定义当timeout发生时要抛出的异常
class TimeOutError(Exception):
pass # 定义装饰器
def retry(func):
@functools.wrap(func)
def wrapper(*arg,**kwarg):
try:
print("first try...")
func(*arg,**kwarg)
except TimeOutError:
print("timeout occurs, retrying...")
func(*arg,**kwarg)
  return wrapper   # 定义download函数
@retry
def download():
print("downloading the photos...")
download_time = random.ranint(1,2)
if download_time>1:
print("the download_time > 1s, time out")
raise TimeOutError
else:
print("download finished.")

如果我们想要带参数的装饰器,则需要再多加一层函数嵌套:

#!/usr/bin/python
#-*- coding:utf-8 -*- import functools
import random # 定义当timeout发生时要抛出的异常
class TimeOutError(Exception):
pass # 定义装饰器
def decorator_download(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*arg,**kwarg):
#try:
# print("first try...")
# func(*arg,**kwarg)
#except TimeOutError:
# print("timeout occurs, retrying...")
# func(*arg,**kwarg)
print(text)
print("first try...")
result = func(*arg,**kwarg)
while result == False:
print("will retry...")
result = func(*arg,**kwarg)
return wrapper
return decorator # 定义download函数
@decorator_download("retry until download finished successfully")
def download():
print("downloading the photos...")
download_time = random.randint(1,2)
if download_time>1:
print("the download_time > 1s, time out")
#raise TimeOutError
return False
else:
print("download finished.")
return True if __name__ == "__main__":
download()

谈谈Python中的decorator装饰器,如何更优雅的重用代码的更多相关文章

  1. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  2. python 中多个装饰器的执行顺序

    python 中多个装饰器的执行顺序: def wrapper1(f1): print('in wrapper1') def inner1(*args,**kwargs): print('in inn ...

  3. 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解

    第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一.    引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...

  4. Python进阶之decorator装饰器

    decorator装饰器 .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB&quo ...

  5. python中面向对象之装饰器

    python面向对象内置装饰器property,staticmethod,classmethod的使用 @property 装饰器作用及使用 作用:面向对象中的方法伪装成属性 使用如下: class ...

  6. Python中的各种装饰器详解

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  7. Python中的单例模式——装饰器实现剖析

    Python中单例模式的实现方法有多种,但在这些方法中属装饰器版本用的广,因为装饰器是基于面向切面编程思想来实现的,具有很高的解耦性和灵活性. 单例模式定义:具有该模式的类只能生成一个实例对象. 先将 ...

  8. python中闭包和装饰器的理解(关于python中闭包和装饰器解释最好的文章)

    转载:http://python.jobbole.com/81683/ 呵呵!作为一名教python的老师,我发现学生们基本上一开始很难搞定python的装饰器,也许因为装饰器确实很难懂.搞定装饰器需 ...

  9. Python中的@property装饰器

    要了解@property的用途,首先要了解如何创建一个属性. 一般而言,属性都通过__init__方法创建,比如: class Student(object): def __init__(self,n ...

随机推荐

  1. SpringCloud是什么?

    参考链接: http://blog.csdn.net/forezp/article/details/70148833 一.概念定义       Spring Cloud是一个微服务框架,相比Dubbo ...

  2. git出现错误原因解释

    原因,在pull下拉代码或者push之前,你本地还有代码没有进行commit. 引起下面的错误.   建议commit后先pull再看看有没有冲突在进行push. git.exe push --pro ...

  3. Hibernate(七):*.hbm.xml配置文件中Set三个属性

    背景: 在上一篇文章中实现双向关联时,其中在Customer.java中我们使用了java.util.List<Order>来关联多的Order.其实还有另外一种实现方法:使用java.u ...

  4. JProfiler简明使用教程

    JProfile是一款性能瓶颈分析工具,监控粒度可以细化到某一个类包,堪称神器!我安装了一下9.11的版本,并简单说说使用方法. 1:创建一个监控任务 2:选择tomcat版本 3:监控远程服务器 4 ...

  5. SSM(Spring)中,在工具类中调用服务层的方法

    因为平时在调用service层时都是在controller中,有配置扫描注入,spring会根据配置自动注入所依赖的服务层. 但因我们写的工具类不属于controller层,所以当所写接口需要调用服务 ...

  6. CentOS 7 安装Boost 1.61

    1. 到官网下载最新版的boost,http://www.boost.org/users/history/version_1_61_0.html 2. 解压: tar zxvf boost_1_61_ ...

  7. JavaScript 随机数相关算法

    // Math.ceil() 返回大于等于数字参数的最小整数(取整函数),对数字进行上舍入 // Math.floor() 返回小于等于数字参数的最大整数,对数字进行下舍入 // Math.round ...

  8. Python模块之 - logging

    日志是非常重要的,最近有接触到这个,所以系统的看一下Python这个模块的用法.本文即为Logging模块的用法简介,主要参考文章为Python官方文档,链接见参考列表. Logging模块构成 组成 ...

  9. ASwipeLayout一个强大的侧滑菜单控件

    Android中侧滑的场景有很大,大部分是基于RecyclerView,但是有些时候你可以动态地addView到一个布局当中,也希望它实现侧滑,所以就产生了ASwipeLayout,该控件不仅支持在R ...

  10. kafka知识体系-kafka设计和原理分析-kafka文件存储机制

    kafka文件存储机制 topic中partition存储分布 假设实验环境中Kafka集群只有一个broker,xxx/message-folder为数据文件存储根目录,在Kafka broker中 ...