Python装饰器(超级基础,新手必看)

(欢迎加群学习qq:651707058)
前言:为了弄明白这个装饰器是个什么鬼,我看了很多东西,从慕课教程,到菜鸟教程,我依然没有很明白,又看了很多博客,感谢感谢感谢!!!现在我终于明白点啥了,虽然自己还不会写,不会用,但是对于小白来说,一定有帮助。(内容比较多,希望能耐心看完)

概念:*python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函的代码前提下给函数增加新的功能*。 (估计你现在有个大致了解了)

加深理解:
初创公司有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需调用基础平台提供的功能即可。

############### 基础平台提供的功能如下 ###############

def f1():
    print 'f1'
def f2():
    print 'f2'
def f3():
    print 'f3'
 def f4():
    print 'f4'

############### 业务部门A 调用基础平台提供的功能 ###############
f1()
f2()
f3()
f4()
############### 业务部门B 调用基础平台提供的功能 ###############
f1()
f2()
f3()
f4()

目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即:基础平台的提供的功能可以被任何人使用。现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。(即概念中所提到的“ 不用更改原函数的代码前提下,给函数增加新的功能(验证))
方法一:
跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。诶,这样一来基础平台就不需要做任何修改了(哈哈,该职员被老板炒了)
方法二:
只对基础平台的代码进行重构,让N业务部门无需做任何修改(他也被炒了)

############### 基础平台提供的功能如下 ############### 
def f1():
    # 验证1
    # 验证2
    # 验证3
    print 'f1'
def f2():
    # 验证1
    # 验证2
    # 验证3
    print 'f2'
def f3():
    # 验证1
    # 验证2
    # 验证3
    print 'f3'
def f4():
    # 验证1
    # 验证2
    # 验证3
    print 'f4'
############### 业务部门不变 ############### 
### 业务部门A 调用基础平台提供的功能### 
f1()
f2()
f3()
f4()
### 业务部门B 调用基础平台提供的功能 ### 
f1()
f2()
f3()
f4()

……简单的方法就不说了,我们直接用今天的装饰器来看一下
方法三:

def w1(func):
    def inner():
        # 验证1
        # 验证2
        # 验证3
        return func()
    return inner
@w1
def f1():
    print 'f1'
@w1
def f2():
    print 'f2'
@w1
def f3():
    print 'f3'
@w1
def f4():
    print 'f4'

———-(现在你不需要明白这个到底怎么写,我只想通过这个例子让你明白,装饰器其实可以很简单的完成很复杂的问题。下面我们来深入了解装饰器)———-

装饰器(一)

例题1:打印函数执行的时间

import time#关于时间的打印可以自行了解
def f1():
    print(time.time())
    print('This is a function.')
f1()

这个函数可以完成题目要求,那么如果我需要有很多的函数来实现打印时间的功能,我们需要像下边的代码一样吗?

import time#关于时间的打印可以自行了解
def f1():
    print(time.time())
    print('This is a function.')
f1()
def f2():
    print(time.time())
    print('这里打印的东西可以是任意的,我主要像表示f1和f2为不同的函数')
f2()
'如果需要还要有很多函数f3,f4,f5等等'

显然,要对很多函数实现打印时间的功能按上述方法就会很麻烦,这时,装饰器就可以很好地解决这个问题。

#还有很重要的一点,我们的Python在语法上遵循“对修改是封闭的,对扩展是开放的”的原则,所以我们这样强行将打印时间的功能加进函数里面是不够好的。

装饰器(二)

import time
def decorator(func):
    def wrapper():
        print(time.time())     #先执行
        func()#返回值(一个函数)   再执行函数f1结果如下
    return wrapper
#以上内容就是一个装饰器,即wrapper被decorator包裹起来,像一个装饰器
def f1():
    print('This is a function')
f=decorator(f1)
f()
#运行结果为
# 1533530657.8872964
#This is a function
'相当于执行了wrapper里面的内容'

可能现在你还无法理解为什么要用这么麻烦的方法来完成,但是这里我想先让大家明白装饰器的基本原理,至于如何使用,先不用太急着了解。
前六行为一个完整装饰器,我们以后需要使用这个模板来实现一个装饰器。

补充内容:代码第五行返回值为一个函数,这个我们要明白一个概念“一切皆对象”,下面我举一个例子来理解一下

def hi(name="yasoob"):
    return "hi " + name
 print(hi())
# output: 'hi yasoob'
# 我们甚至可以将一个函数赋值给一个变量,比如
greet = hi
# 我们这里没有在使用小括号,因为我们并不是在调用hi函数
# 而是在将它放在greet变量里头。我们尝试运行下这个
print(greet())
# output: 'hi yasoob'
# 如果我们删掉旧的hi函数,看看会发生什么!
del hi
print(hi())
#outputs: NameError
print(greet())
#outputs: 'hi yasoob'

这个我就不做过多解释了。

装饰器(三)

这一节我们要引出装饰器的核心部分——语法糖(很好吃的名字)
我们之所以要引出语法糖是因为在上一段代码中我们在开头写出了一个装饰器,原本是想让代码更简洁,然而我们却又在代码最后使用以下方法来完成调用,不可否认,这个方法很麻烦,所以,语法糖来解决这个问题了。

f=decorator(f1)
f()

我们在使用装饰器的时候要明白不管我们的装饰器有多麻烦,我们只需要求调用的时候简单即可,而且可以实现写一次装饰器而实现多个函数f1,f2,f3…..的调用,会很方便。

import time
def decorator(func):
    def wrapper():
        print(time.time())     
        func()
    return wrapper
@decorator#这个就是所谓的语法糖,有了它,我们就可以通过直接调用f1来实现调用装饰器
def f1():
    print('This is a function')
f1()#这样就实现了简单调用的原则
#运行结果为
# 1533530657.8872964
#This is a function

装饰器最大的优势就是不改变原来的调用方式,即:我们需要调用f1,使用装饰器我们仍然是通过调用f1来增加装饰器里的功能。

装饰器(四)

我们上一节所使用的f1为无参函数,下面我们来实现一个参数或者多个参数的使用。

import time
def decorator(func):
    def wrapper(func_name):#也要传入参数
        print(time.time())
        func(func_name)#也要传入参数
    return wrapper
@decorator
def f1(func_name):#根据需求我们需要传入参数
    print('This is a function '+func_name)
f1('test1')
#运行结果为
# 1533530657.8872964
#This is a function test1

以上我们实现了一个参数的使用,接下来我们重点看一下多个参数,或者未知个数参数的使用。

'如果一个装饰器只能完成一个函数的使用,那将失去意义,所以我们要实现未知函数参数个数的调用'
import time
def decorator(func):
    def wrapper(*args):#*args为可变参数
        print(time.time())
        func(*args)
    return wrapper
@decorator
def f1(func_name):
    print('This is a function '+func_name)
@decorator
def f2(func_name1,func_name2):
    print('This is a function '+func_name1)
    print('This is a function '+ func_name2)
f1('test1')
f2('test2','test2')
#运行结果为
#1533534463.567321
#This is a function test1
#1533534463.567321
#This is a function test2
#This is a function test2

下面我们用**kw实现了任意参数形式的函数的调用,是一个比较完整地装饰器使用方法

import time
def decorator(func):
    def wrapper(*args,**kw):#kw为关键字参数(可任意命名)
        print(time.time())
        func(*args,**kw)
    return wrapper
@decorator
def f1(func_name):
    print('This is a function named'+func_name)
@decorator
def f2(func_name1,func_name2,**kw):
    print('This is a function named' + func_name1)
    print('This is a function named' + func_name2)
    print(kw)
f1('test func')
f2('test func1','test func2',a=1,b=2,c='123')
#运行结果
#1533534886.485952
#This is a function namedtest func
#1533534886.485952
#This is a function namedtest func1
#This is a function namedtest func2
#{'a': 1, 'c': '123', 'b': 2}

补充内容:
**kw的使用(以字典的形式输出)

def f2(func_name1,func_name2,**kw):
    print('This is a function named' + func_name1)
    print('This is a function named' + func_name2)
    print(kw)
f2('test func1','test func2',a=1,b=2,c='123')
#运行结果
#This is a function namedtest func1
#This is a function namedtest func2
#{'a': 1, 'c': '123', 'b': 2}

以上内容就是一个装饰器的正确使用方法,但我们到底应该在什么情况下会用到装饰器呢,需要我们更深入的学习(由于本人也是刚刚接触装饰器,不能为大家介绍了,不过希望我的一点小小的见解能让大家对装饰器有初步的了解)

猜你喜欢

转载自blog.csdn.net/qq_42849332/article/details/81453287