温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

python基础四:装饰器

发布时间:2020-08-10 13:53:42 来源:网络 阅读:363 作者:琴酒网络 栏目:编程语言

装饰器本质:就是函数,功能是为其他函数添加附加功能

装饰器原则:

  1. 不修改被修饰函数的源代码
  2. 不修改修饰函数的调用方式

装饰器的知识储备:

装饰器 = 高阶函数 + 函数嵌套 + 闭包

初识装饰器

先看一个需求:下面这个函数用来计算1到20的和

def calc(l):
    res = 0
    for i in l:
        time.sleep(0.01)
        res += i
    return res
result = calc(range(1,21))
print(result)

但现在需求有变,不仅要计算1到20的和,还需要计算该函数运行的时间,此时装饰器就应需而生

import time
def timer(func):
    def wrapper(*args,**kwargs):
        start_time = time.time()
        res = func(*args,**kwargs)
        stop_time = time.time()
        print('函数运行的时间为:%s' % (stop_time - start_time))
        return res
    return wrapper
@timer
def calc(l):
    res = 0
    for i in l:
        time.sleep(0.01)
        res += i
    return res
result = calc(range(1,21))
print(result)

运行结果如下:

函数运行的时间为:0.2048475742340088
210

上面的timer函数就是calc函数的装饰器

高阶函数

高阶函数定义:
1.函数接收的参数是一个函数名

2.函数的返回值是一个函数名

3.满足上述条件任意一个,都可称之为高阶函数

高阶函数示例

def foo():
    print('我的函数名作为参数传给高阶函数')
def gao_jie1(func):
    print('我就是高阶函数1,我接收的参数名是%s' %func)
    func()

def gao_jie2(func):
    print('我就是高阶函数2,我的返回值是%s' %func)
    return func

gao_jie1(foo)
gao_jie2(foo)

把函数当作参数传给高阶函数

#高阶函数应用1:把函数当做参数传给高阶函数
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
timmer(foo)
#总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式

函数返回值是函数名

#高阶函数应用2:把函数名当做参数传给高阶函数,高阶函数直接返回函数名
import time
def foo():
    print('from the foo')

def timmer(func):
    start_time=time.time()
    return func
    stop_time=time.time()
    print('函数%s 运行时间是%s' %(func,stop_time-start_time))
foo=timmer(foo)
foo()
#总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能

高阶函数总结
1.函数接收的参数是一个函数名
  作用:在不修改函数源代码的前提下,为函数添加新功能,
  不足:会改变函数的调用方式
2.函数的返回值是一个函数名
  作用:不修改函数的调用方式
  不足:不能添加新功能

函数嵌套

def father(name):
    print('from father %s' %name)
    def son():
        print('from son')
        def grandson():
            print('from grandson')
        grandson()
    son()
father('Poe')

闭包

'''
闭包:在一个作用哉里放放定义变量,相当于打了一个包
'''
def father(name):
    def son():
        print('My father is %s' %name)
        def grandson():
            print('my grandpa is %s' %name)
        grandson()
    son()
father('Poe')

无参数装饰器

无参装饰器=高级函数+函数嵌套

基本框架

'''
这就是一个实现 装饰器最基本的架子
'''
def timer(func):
    def wrapper():
        func()
    return wrapper()

回到上面需要计算函数运行时间的需求,在不使用装饰器的情况下加上以下代码

import time
def timer(func):
    def wrapper():
        startTime = time.time()
        func()
        stopTime = time.time()
        print('函数运行时间为:%s' % (stopTime - startTime))
    return wrapper

def test():
    time.sleep(3)
    print('test函数运行完毕')

res = timer(test)
res()

使用装饰器

import time
def timer(func):
    def wrapper():
        startTime = time.time()
        func()
        stopTime = time.time()
        print('函数运行时间为:%s' % (stopTime - startTime))
    return wrapper
@timer  #相当于test = timer(test)
def test():
    time.sleep(3)
    print('test函数运行完毕')
test()

返回值问题
如果test函数中有返回值怎么返回呢?test函数被调用时,实质就是调用wrapper函数,如果要返回test函数中的值,必须要在wrapper函数中将该值返回

import time

def timer(func):
    def wrapper():
        startTime = time.time()
        res = func()
        stopTime = time.time()
        print('该函数运行时间为:%s' % (stopTime - startTime))
        return res
    return wrapper

@timer
def test():
    time.sleep(1)
    print('该函数运行完毕')
    return '这是test的返回值'
res = test()        #实质调用的是wrapper函数
print(res)

带参数的装饰器

import time

def timer(func):
    def wrapper(*args,**kwargs):
        startTime = time.time()
        res = func(*args,**kwargs)
        stopTime = time.time()
        print('该函数运行时间为:%s' % (stopTime - startTime))
        return res
    return wrapper

@timer  #test = timer(test)
def test(name,age):
    time.sleep(1)
    print('该函数运行完毕,name is %s,age is %s' %(name,age))
    return '这是test的返回值'
res = test('andy',18)        #实质调用的是wrapper函数
print(res)

补充知识:解压序列

>>> a,b,c=(2,3,4)
>>> a
2
>>> b
3
>>> c
4

a , b, c变量要与元组中的元素一一对应才能取到值
那么再看一个实例:

>>> l=[1,2,3,4,5,6,7,8]

利用序列的方法如何取得上面列表中的第一个元素与最后一个元素

>>> l=[1,2,3,4,5,6,7,8]
>>> l
[1, 2, 3, 4, 5, 6, 7, 8]
>>> a,*_,c=l
>>> a
1
>>> c
8
>>> a,*b,c=l
>>> a
1
>>> b
[2, 3, 4, 5, 6, 7]
>>> c
8

注意:号代表除a,c变量外所有元素,号后面必须要有一个变量,使用下划线表示*号代表的变量不想被取出

该方法可用来交换两个变量的值:

>>> a=1
>>> b=2
>>> a,b=(b,a)
>>> a
2
>>> b
1

装饰器示例

user_list = [
    {'name':'andy','passwd':'123'},
    {'name':'bruce','passwd':'123'},
    {'name':'poe','passwd':'123'},
    {'name':'jacky','passwd':'123'},
]
current_dic = {'username':None,'login':False}

def auth_func(func):
    def wrapper(*args,**kwargs):
        if current_dic['username'] and current_dic['login']:
            res = func(*args,**kwargs)
            return res
        username = input('username:').strip()
        password = input('password:').strip()
        for user_dic in user_list:
            if username == user_dic['name'] and password == user_dic['passwd']:
                current_dic['username'] = username
                current_dic['login'] = True
                res = func(*args,**kwargs)
                return res
        else:
            print('用户名或密码错误')
    return wrapper

@auth_func
def index():
    print('欢迎来到JD主页' )
@auth_func
def home(name):
    print('welcome %s to home' % name)
@auth_func
def shopping(name):
    print('%s的购物车里有%s,%s,%s' %(name,'奶茶','妹妹','牙膏'))

print('before : ',current_dic)
index()
home('andy')
shopping('andy')
print('after: ',current_dic)

代码执行结果:

before :  {'username': None, 'login': False}
username:andy
password:123
欢迎来到JD主页
welcome andy to home
andy的购物车里有奶茶,妹妹,牙膏
after:  {'username': 'andy', 'login': True}
向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI