今天我们来介绍一下可以提升python代码逼格的东西——装饰器。在学习装饰器之前我们先来复习一下函数的几个小点,方便更好的理解装饰器的含义。

一、知识点复习

1, 在函数中f1和f1()有什么不同,f1:表示的是将整个函数看作一个整体;f1():表示执行f1函数,下面通过一个例子来看一下:

1
2
3
4
5
def f1():
    print('f1')
 
f1                    #代表函数体本身,什么也不操作
f1()                  #代表执行函数

2、lambda函数:

1
2
3
4
f1 = lambda f1:f1 +100
print(f1(50))
 
150

3、Python的从上到下的执行方式:

1
2
3
4
5
6
7
def f1():              #根据Python从上而下的原则,先将f1函数加载到内存
    print('f1')        #指向print('f1'),当下面在出现f1函数时指针会指向
def f1():              #新的值,跟变量赋值的原理一样
    print('f2')
f1()
 
f2

二、装饰器

下面通过一个需求来介绍装饰器在代码中的应用和如何提高代码逼格,需求如下:

B市某创业公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需要调用基础平台提供的功能即可。具体情况如下:

1
2
3
4
5
6
7
8
#基础部门提供的功能如下:
 
def f1():
    print('f1')
def f2():
    print('f2')
def f3():
    print('f3')
1
2
3
4
5
#其他业务部门调用的方法如下:
 
f1()
f2()
f3()

目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写底层代码时没有关注验证相关的问题,即:基础平台的提供的功能可能被任何人使用。现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。

现在老大把工作交给了小明,他是这么做的:

1
小明本身比较low,于是去找每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证,这样基础平台就不用修改代码了。

当天小明就被开除了,老大语重心长的说回去好好学学Python吧。

老大又把活交给小明2号 ,小明2号比小明要聪明一点,心想傻X才会一个部门一个部门去找呢,于是重构了基础平台的代码,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#基础平台代码:
def f1():
    #验证
    print('f1')
def f2():
    #验证
    print('f2')
def f3():
    #验证
    print('f3')
 
#其他业务部门调用基础平台代码不变:
f1()
f2()
f3()

就这样小明2号修改了一周交差了,然而命运总是这么爱捉弄人,几个部门开会说加验证太麻烦,要去掉,又交给了小明2号,这次老大给了排期,一天之内做完,小明2号懵逼了,跟老大说完不成,于是老大去看了小明2号的修改的代码,然后就没有然后了,小明2号也光荣的退出了历史舞台。

经过两次以后,老大已经下定决心要招个牛逼的Python开发,广发英雄帖请来了小明3号,将上面的工作交给了他,下面来看看小明3号是如何修改的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#基础平台提供的功能如下:
 
def check_login():
    #验证
    pass
 
def f1():
    check_login()
    print('f1')
def f2():
    check_login()
    print('f2')
...
 
#其他业务部门调用方法不变:
f1()
f2()
...

修改完以后,老大看完代码很欣慰,对小明3号说:

写代码要遵循开发封闭的原则,虽然在这个原则是用在面向对象开发,但是也适用于函数式编程,简单来说,规定已经实现的功能代码不允许被修改,但可以被扩展,即:

⊙封闭:已经实现的功能代码块

⊙开放:对扩展开放

如果将开放封闭原则应用在上述需求中,那么就不允许在函数f1、f2、f3的内部进行修改代码,老大说现在给你一个举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def outer(func):
    def inner():
        #check1
        #check2
        return func()
    return inner
 
@outer
def f1():
    print('f1')
 
@outer
def f2():
    print('f2')
...

上述代码,也是仅仅对基础平台代码进行修改,就可以实现在其他人调用函数f1、f2、f3之前都进行[验证]操作,并且其他业务部门无需做任何操作。

小明3号有点疑惑的问,这段代码的内部执行原理是什么呢?

老大说想知道,晚上洗干净等着我,这时小明3号菊花一紧,我X,老大还有这癖好,老大:逗你的,实际内部实现很简单,下面给你讲一下:

单独以f1为例:

1
2
3
4
5
6
7
8
9
10
def outer(func):
    def inner():
        #check
        #check
        return func()
    return inner
 
@outer
def f1():
    print('f1')

当写完这段代码后(函数未被执行),Python解释器会从上到下解释代码,步骤如下:

1,def outer(func):     将outer函数加载到内存

2,@outer                  调用装饰器

从表面上看解释器仅仅会解释两句代码,因为函数在没有被调用之前其内部代码不会被执行,但是

@outer这句代码里却大有文章。

@函数名是Python的一种语法糖:  

1,执行outer函数并将@outer下面的函数作为outer函数的参数,即:@outer 就等价于outer(f1)。

1
2
3
4
5
6
7
def inner():
 
    #check
 
    return f1()  #fun是参数,此时就相当于整个f1函数塞进了另一个函数中
 
return inner     #返回inner,inner代表的是函数,而不是去执行inner函数

2,将执行完的outer函数返回值赋值给@outer下面的函数的函数名。

1
2
3
4
5
6
7
8
9
10
11
12
#outer的返回值为:
 
def outer(func):
    def inner():
        #check
        return f1()       #此时的func已经是原来的f1函数
    return inner
 
#然后,将返回值在重新赋值给f1,即:
新f1 = def  inner():
            #check
            return f1()

这样一来,以后业务部门想要执行f1函数时,就会执行新f1函数,在新f1函数内部先验证在执行原来的f1函数,再将原来f1函数的返回值返回给业务调用者。

老大:回去好好研究一下吧,不懂洗干净晚上来我家。。。。

三、装饰器参数

1、被装饰的函数有参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#有一个参数时:
 
def outer(func):
    def inner(args):
        #check1
        #check2
        return func(args)
    return inner
 
@outer
def f1(args):
    print('f1')
 
#有两个参数时:
 
def outer(func):
    def inner(arg1,arg2):
        #check1
        #check2
        return func(arg1,arg2)
    return inner
 
@outer
def f1(arg1,arg2):
    print('f1')
 
 
#如果有多个参数怎么办,这里就用到了我们之前学的万能参数*args、**kwargs
 
def outer(func):
    def inner(*args,**kwargs):
        #check1
        #check2
        return func(*args,**kwargs)
    return inner
 
@outer
def f1(arg1,arg2,arg3,arg4):
    print('f1')

2、一个函数被多个装饰器装饰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def outer1(func):
    def inner(*args,**kwargs):
        #check1
        #check2
        return func(*args,**kwargs)
    return inner
  
def outer2(func):
    def inner(*args,**kwargs):
        #check1
        #check2
        return func(*args,**kwargs)
    return inner
  
@outer1
@outer2
def f1(a​rg1,arg2,arg3,arg4):
    print('f1')

​   3、双重装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def Before(request,kargs):
    print('before')
 
def After(request,kargs):
    pow('After')
 
def Filter(brefore_func,after_func):
    def outer(main_func):
        def wrapper(request,kargs):
            brefore_result = brefore_func(request,kargs)
            if (brefore_result != None):
                return brefore_result
            main_result = main_func(request,kargs)
            if (main_result != None):
                return main_result
        return wrapper
    return outer
 
@Filter(Before,After)
def Index(request,kargs):
    print('index')

Python基础(八)装饰器的更多相关文章

  1. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

  2. 十. Python基础(10)--装饰器

    十. Python基础(10)--装饰器 1 ● 装饰器 A decorator is a function that take a function as an argument and retur ...

  3. [python基础]关于装饰器

    在面试的时候,被问到装饰器,在用的最多的时候就@classmethod ,@staticmethod,开口胡乱回答想这和C#的static public 关键字是不是一样的,等面试回来一看,哇,原来是 ...

  4. Day11 Python基础之装饰器(高级函数)(九)

    在python中,装饰器.生成器和迭代器是特别重要的高级函数   https://www.cnblogs.com/yuanchenqi/articles/5830025.html 装饰器 1.如果说装 ...

  5. 1.16 Python基础知识 - 装饰器初识

    Python中的装饰器就是函数,作用就是包装其他函数,为他们起到修饰作用.在不修改源代码的情况下,为这些函数额外添加一些功能,像日志记录,性能测试等.一个函数可以使用多个装饰器,产生的结果与装饰器的位 ...

  6. 学习PYTHON之路, DAY 5 - PYTHON 基础 5 (装饰器,字符格式化,递归,迭代器,生成器)

    ---恢复内容开始--- 一 装饰器 1 单层装饰器 def outer(func): def inner(): print('long') func() print('after') return ...

  7. python基础-----函数/装饰器

    函数 在Python中,定义一个函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. 函数的优点之一是,可以将代码块与主程 ...

  8. python基础之装饰器(实例)

    1.必备 #### 第一波 #### def foo(): print 'foo' foo #表示是函数 foo() #表示执行foo函数 #### 第二波 #### def foo(): print ...

  9. 【Python基础】装饰器的解释和用法

    装饰器的用法比较简单,但是理解装饰器的原理还是比较复杂的,考虑到接下来的爬虫框架中很多用到装饰器的地方,我们先来讲解一下. 函数 我们定义了一个函数,没有什么具体操作,只是返回一个固定值 请注意一下缩 ...

  10. Python基础之装饰器

    1.什么是装饰器? Python的装饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然 ...

随机推荐

  1. gerrit+gitlab整合调试

  2. linux centos7 安装mysql-5.7.17教程(图解)

    1系统约定安装文件下载目录:/data/softwareMysql目录安装位置:/usr/local/mysql数据库保存位置:/data/mysql日志保存位置:/data/log/mysql 2下 ...

  3. Rails5 View Document

    更新: 2017/06/11 更新: 2017/06/15 加粗,submit必须放在form_for内部 更新: 2017/06/23 对待完成的追加# TODO:                 ...

  4. echart 参数 vue配置 图文展示

    https://blog.csdn.net/she_lover/article/details/51448967 https://blog.csdn.net/n_meng/article/detail ...

  5. 如何保证access_token长期有效--微信公众平台开发

    http://blog.csdn.net/qq_33556185/article/details/52758781 import javax.servlet.ServletContext; impor ...

  6. [笔试面试题] 10-C和C++区别相关

    1 C和C++有什么不同? 机制不同:C是面向过程的(但C也可以编写面向对象的程序):C++是面向对象的,提供了类.但是,C++编写面向对象的程序比C容易. 适用领域不同:C适合要求代码体积小的,效率 ...

  7. 神奇的Object.defineProperty

    vue.js和avalon.js 都是通过它实现双向绑定的. 对象是由多个名/值对组成的无序的集合.对象中每个属性对应任意类型的值.定义对象可以使用构造函数或字面量的形式: var obj={}; o ...

  8. phpstudy初级总结

    1.问题一 问题症状:访问http://localhost/phpMyWind/install/不出现安装或登录页面 考虑一下情况: 1.是否打开了PHPstudy, (当Apache不能启用时,考虑 ...

  9. 本地编译全志R系列的步骤(Ubuntu16.04.4版本)

    本地编译全志R系列的步骤(Ubuntu16.04.4版本) 2018/6/14 9:32 版本:V1.0 0.获取全志R系列的Android源码包: 请通过渠道/代理商/方案公司获取全志R系列的And ...

  10. 联想 K5 Pro(L38041)免解锁BL 免rec 保留数据 ROOT Magisk Xposed 救砖 ZUI 5.0.188

    >>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...