python中的装饰器

什么是装饰器

"""
 装饰器:
 把一个函数当作参数,返回一个替代版的函数
 本质上就是一个返回函数的函数

 "在不改变原函数的基础上,给函数增加功能"
"""

通过几个列子来观察装饰器的作用

def outer(func):
    def inner(age):
        if age < 0:
            age = 0
        func(age)
    return inner


@outer #语法糖  #say=outer(say)
# 使用@符号将装饰器应用到函数
def say(age):
    print('man is %d years old' %(age))

say(-10)

在这里插入图片描述

def desc(fun):  # 需要传递一个函数,要装饰的函数
    def add_info():  # 装饰器函数里要嵌套函数
        print('元旦快乐~')
        fun()
        #print('欢迎光临西部开源~')
    return add_info    # 返回值是嵌套的函数对象

@desc   # 如何调用装饰器(两种方式)
def login():
    print('login....')

# login = desc(login)  # 返回值是一个函数
# login()
@desc
def logout():
    print('logout...')

@desc
def savemoney():
    print('存钱...')

@desc
def transfermoney():
    print('转账...')


login()
logout()
savemoney()
transfermoney()

在这里插入图片描述

装饰器的练习1
使用装饰器生成一个计时器

import time


def timecal(fcb):
    def ing(*args, **kwargs):
        # 在执行函数之前记时:
        start_time = time.time()
        # 然后执行函数
        fcb(*args,**kwargs)
        # 执行函数之后记时:
        end_time = time.time()
        print('函数的执行时间为%.6fs' % (end_time - start_time))

    return ing

@timecal
def fun_list(n):
    print([i * 2 for i in range(n)])

@timecal
def fun_map(n):
    print(list(map(lambda x:x*2,range(n))))

fun_list(1000)
fun_map(1000)

在这里插入图片描述

在使用装饰器是如何查看原函数名和帮助文档信息

import time
import functools

def timecal(fcb):
    """这是一个装饰器timecal"""
    @functools.wraps(fcb)
    def ing(*args, **kwargs):
        """这是一个ing函数"""
        # 在执行函数之前记时:
        start_time = time.time()
        # 然后执行函数
        res= fcb(*args,**kwargs)
        # 执行函数之后记时:
        end_time = time.time()
        print('函数的执行时间为%.6fs' % (end_time - start_time))
        return res
    return ing

@timecal
def fun_list(n):
    """这是list函数,被timecal装饰"""
    return [(i * 2 for i in range(n))]

@timecal
def fun_map(n):
    """这是map函数,被timecal装饰"""
    return map(lambda x:x*2,range(n))

def zjs():
    """这是zjs函数"""
    print('hhhhha')



# print(fun_list(1000))
# print(fun_map(1000))
print(fun_list.__doc__)
print(fun_list.__name__)
print(zjs.__doc__)
print(zjs.__name__)

在这里插入图片描述
如图为未导入functools时所打印的函数名和帮助文档信息,将原函数的函数名和帮助文档信息覆盖,为了现实原函数的函数名和帮助文档信息,导入functools
在这里插入图片描述
如图显示的则是原函数的函数名和帮助文档信息
总结:注释掉@funtools后发现print(fun_list.doc)print(fun_list.name)打印的是装饰器中的ing帮助文档信息和函数名
不管有没有funtools,未被装饰的函数zjs仍旧打印的是他自己本身的函数名和帮助文档信息

之前写过的管理员登陆系统我们也可以用装饰器来完成

import functools
import inspect

def is_admin(fun):
    @functools.wraps(fun)
    def zjs(*args,**kwargs):
        #inspect.getcallargs返回一个字典,key值:形参 value值:对应的实参
        insp_res = inspect.getcallargs(fun,*args,**kwargs)
        print('inspect的返回值是:%s' %(insp_res))
        if insp_res.get('name')=='root':
            res = fun(*args,**kwargs)
            return  res
        else:
            print('not root cannot to operate')
    return zjs


@is_admin
def addstu(name):
    print('添加学生信息---')

addstu('root')
addstu('redhat')

在这里插入图片描述

装饰器练习

"""
# 创建装饰器, 要求如下:
# 1. 创建add_log装饰器, 被装饰的函数打印日志信息;
# 2. 日志格式为: [字符串时间] 函数名: xxx, 运行时间:xxx, 运行返回值结果:xxx
"""
import functools
import time


def add_log(fun):
    @functools.wraps(fun)
    def zjs(*args, **kwargs):
        start_time = time.time()
        res = fun(*args, **kwargs)
        end_time = time.time()
        print('[%s] 函数名:%s,运行时间:%.6f,运行返回值:%d'
              % (time.ctime(), fun.__name__, end_time - start_time, res))
        return res

    return zjs


@add_log
def log(x, y):
    return x * y


log(2, 5)

在这里插入图片描述

当有多个装饰器时是如何调用的

def zjs1(fun):
    print('zjs----1')

    def ing1(*args, **kwargs):
        print('ing----1')
        return fun(*args, **kwargs)

    return ing1


def zjs2(fun):
    print('zjs----2')

    def ing2(*args, **kwargs):
        print('ing----2')
        return fun(*args, **kwargs)

    return ing2


"""
当有多个装饰器的时候,从下到上调用
真实的warpper内容是从上到下执行的
"""


@zjs2
@zjs1
def add(x):
    print('add-x')
    return x + 1


add(5)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值