http://book.pythontips.com/en/latest/decorators.html

在《Built-in Functions(3.6)》和《Python上下文管理器》两篇笔记中,已经有了装饰器初步的示例,本篇结合一个高露洁大学牛人的博客来系统的解释下python中装饰器的作用。

一、首先提出一个统一的概念

Decorators are functions which modify the functionality of other functions. They help to make our code shorter and more Pythonic.

装饰器(也可以叫修饰器)的作用就是改变其他函数的运作方式,这可以使得代码更加简洁和Pythonic。

二、接下来一步一步的接近decorator

首先,函数是可以返回函数的,示例如下:

def hi(name="Leo"):
def greet():
return "恭喜!" def welcome():
return "欢迎!" if name == "Leo":
return greet
else:
return welcome a = hi()
print(a)
# <function greet at 0x7f2143c01500>
# 这说明这里的a就是greet(),因为默认name="Leo",而return是不带括号的greet,这会返回一个函数而不是函数执行后的结果 print(a())
# 恭喜!
# 如果像上边那样print(a)那么得到的只是一个greet()函数,但如果是print(a())那么函数就会被执行,因此返回的是greet() return的内容

然后,函数当然也可以作为其他函数的参数:

def hi():
return "hi Leo!" def doSomethingBeforeHi(func):
print("执行"+func.__name__+"()之前先打个666")
print(func()) doSomethingBeforeHi(hi)
# 执行hi()之前先打个666
# hi Leo!

到这里再次提出一个概念就可以很好被理解了,即:Python中所有的东西都可以看做一个object。无论是自定义函数还是基础的数据类型亦或是自定义的class或者实例,万物皆对象(很熟悉吧)。这些对象可以被作为输入也可以被返回。

而装饰器的核心也就是上边提出的:为了使代码更加简洁。因为把所有功能写在一个函数里会显得很臃肿,因此把一部分通用功能先写出来,作为另一个函数的前置,这可以使得代码更加轻便同时也可以对这些函数复用。

三、好,接下来可以写一个decorator了

# coding=utf-8
def decorator(func):
def doSomethingBeforeFunc():
print("办正事之前先来点其他的。")
func()
return doSomethingBeforeFunc def func():
print("真正要做的事在这里。") func=decorator(func)
func()
# 办正事之前先来点其他的。
# 真正要做的事在这里。

我们可以看到func函数本来只是想打印一句话“真正要做的事在这里”,但是由于经过了decorator()的处理其行为发生了变化多打印了一句,这是因为decorator将func作为输入参数,并return了一个封装了func的函数,这个封装好的函数不仅包含了func()的功能还包含了print("办正事之前先来点其他的。")的功能,因此执行func=decorator(func)后func就不是原来的func了,实际上是doSomethingBeforeFunc()。

而常见的装饰器的调用方式并非上述func=decorator(func),而是使用@符号。

以下写法为,在定义func之前使用@decorator 调用装饰器,相当于在定义func之后执行了func=decorator(func):

# coding=utf-8
def decorator(func):
def doSomethingBeforeFunc():
print("办正事之前先来点其他的。")
func()
return doSomethingBeforeFunc
@decorator
def func():
print("真正要做的事在这里。") func()
# 办正事之前先来点其他的。
# 真正要做的事在这里。

这段代码与上面的代码的作用是一模一样的,只不过下边的写法更为常见,更Pythonic(更对新手不友好)。

四、上述代码的一个BUG

如果我们对上述代码中使用了decorator后的func打印__name__会如何?很容易猜到得到的肯定是doSomethingBeforeFunc这个名字,这一般不是我们想要的。

# coding=utf-8
from functools import wraps
def decorator(func):
@wraps(func)
def doSomethingBeforeFunc():
print("办正事之前先来点其他的。")
func()
return doSomethingBeforeFunc @decorator
def func():
print("真正要做的事在这里。") func()
print(func.__name__)
# 办正事之前先来点其他的。
# 真正要做的事在这里。
# func

通过引入functools的wraps方法,可以解决__name__的显示问题。至于wraps是通过什么样的机制实现的,源码实在是太绕了就不去看了。简单来说就是wraps可以让我们获取func()被修饰器修饰之前的各种内置属性。

五、Decorator的经典使用场景

在Python中装饰器一个很经典的使用场景是Django里常见的需要密码验证的时候,举个例子:

# coding=utf-8
from functools import wraps
def require_login(func):
@wraps(func)
def new_func(*args, **kwargs):
auth = request.authorization
if not auth or check_auth(auth.username, auth.password):
authenticate()
return func(*args, **kwargs)
return new_func @require_login
def func():
print("浏览页面中...")

上述只是一段伪代码示例,django中可以直接调用相关的模块:

from django.contrib.auth.decorators import login_required

六、不仅仅是decorator函数,还可以是decorator类

之前的示例全都是修饰器函数,实际上修饰器还可以是类。只要类可以像函数那样被调用就可以了:

# coding=utf-8
class Decorator(object):
def __init__(self , func):
self.func = func
def __call__(self, *args, **kwargs): # 只要重写类的__call__方法就可以将类当做函数调用
print("嘿!孙贼!")
return self.func(*args, **kwargs) @Decorator
def Charge():
print("正在向法爷冲锋!!!") Charge()

Python装饰器(Decorators )的更多相关文章

  1. 【低门槛 手把手】python 装饰器(Decorators)原理说明

    本文目的是由浅入深地介绍python装饰器原理 装饰器(Decorators)是 Python 的一个重要部分 其功能是,在不修改原函数(类)定义代码的情况下,增加新的功能 为了理解和实现装饰器,我们 ...

  2. Python 装饰器(Decorators) 超详细分类实例

        Python装饰器分类 Python 装饰器函数: 是指装饰器本身是函数风格的实现; 函数装饰器: 是指被装饰的目标对象是函数;(目标对象); 装饰器类 : 是指装饰器本身是类风格的实现; 类 ...

  3. Python装饰器Decorators

    def hi(name="yasoob"): return "hi " + name print(hi()) # 我们甚至可以将一个函数赋值给一个变量,比如 g ...

  4. 关于python装饰器(Decorators)最底层理解的一句话

    一个decorator只是一个带有一个函数作为参数并返回一个替换函数的闭包. http://www.xxx.com/html/2016/pythonhexinbiancheng_0718/1044.h ...

  5. Python装饰器与面向切面编程

    今天来讨论一下装饰器.装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数 ...

  6. python -- 装饰器的高级应用

    装饰器和装饰器模式装饰器模式是面向对象的一种设计模式,支持将行为动态增加到已经存在的对象上.当装饰一个对象的时候,就表示独立与其他类实例对象,为该对象扩展了新的功能. python的装饰器不是装饰器模 ...

  7. Python第二十六天 python装饰器

    Python第二十六天 python装饰器 装饰器Python 2.4 开始提供了装饰器( decorator ),装饰器作为修改函数的一种便捷方式,为工程师编写程序提供了便利性和灵活性装饰器本质上就 ...

  8. python装饰器的详细解析

    什么是装饰器? python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于 ...

  9. Python高级特性: 12步轻松搞定Python装饰器

    12步轻松搞定Python装饰器 通过 Python 装饰器实现DRY(不重复代码)原则:  http://python.jobbole.com/84151/   基本上一开始很难搞定python的装 ...

随机推荐

  1. 自学python中的心得

    以后的日子里我将与可爱的亲们一起度过我自学python的岁月,请博客园里的大佬们监督与见证.

  2. k8s 开船记-首航:博客站点从 docker swarm 切换到 k8s

    昨天晚上,我们将博客站点的生产环境从 docker swarm 集群切换到了 k8s 集群,开船到目前,航行非常平稳,可以说首航成功! k8s 集群是我们用10台阿里云服务器自己搭建的,1台 mast ...

  3. apache mpms和php概述

    当设置一个Apache + PHP服务器来运行你的PHP应用程序时,有许多配置参数需要处理. 最重要的是php服务器Api(server api:sapi),它决定了Apache将如何运行PHP脚本. ...

  4. 使用dva改造旧项目的数据流方案

     前言 最近在给自己的脚手架项目转到TypeScript时,遇到了一些麻烦. 项目之前采用的是react + react-redux + redux-thunk + redux-actions +re ...

  5. ACM-ICPC 2018 焦作赛区网络预赛 G题 Give Candies

    There are NN children in kindergarten. Miss Li bought them NN candies. To make the process more inte ...

  6. POJ 3281 Dining(网络流-拆点)

    Cows are such finicky eaters. Each cow has a preference for certain foods and drinks, and she will c ...

  7. CodeForces985C-Liebig's Barrels

    描述 题解 二分加贪心.先确保前 ii 桶可以分配为相邻的 kk 个,并且保证 a[i∗k+j]−a[1]<=la[i∗k+j]−a[1]<=l,这样就能保证所有的差不大于 ll,如果不能 ...

  8. 分享和探讨——如何测试Java类的线程安全性?

    缺乏线程安全性导致的问题很难调试,因为它们是零星的,几乎不可能有意复制.你如何测试对象以确保它们是线程安全的? 我在最近的学习中和优锐课老师谈到了这个问题.现在,是时候以书面形式进行解释了.线程安全是 ...

  9. Linux-tac、diff、tree、echo、seq、重定向

    1.tac  方向输出文件,最后一行放在第一行的位置输出 2.diff  比较文件的内容 vimdiff:在vim中比较 3. tree  树状图显示目录内容 -d 只显示目录   -L  树状 目录 ...

  10. irules

    BIG-IP系统iRules基本概念_v11.6.1 2017年10月10日 00:35:16 ifelif 阅读数:1097   1 iRules介绍 什么是iRule iRule是BIG-IP本地 ...