• python全栈学习--day12(函数高级应用-带参数的装饰器,多个装饰器装饰一个函数)


    函数的执行时,*打散

    函数的定义时,*聚合

    from functools import  wraps
    
    def wrapper(f):
        @wraps(f)
        def inner(*args,**kwargs):
            '''执行函数之前的相关操作'''
            ret = f(*args,**kwargs)
            '''执行函数之后的相关操作'''
            return ret
        return inner
    @wrapper
    def func1(*args):
        print(666)
        return args
    print(func1(*[1,2,3]))
    一,函数的有用信息
    1.函数名 使用__name__方法
    2.函数的解释 使用__doc__方法获取
    举个例子:
    def func1():
        """
        此函数是完成登陆的功能,参数分别是...作用。
        :return: 返回值是登陆成功与否(True,False)
        """
        print(666)
        # print(func1.__name__)
        # print(func1.__doc__)
        return True
    func1()
    print(func1.__name__) #获取函数名
    print(func1.__doc__) #获取函数名注释说明
    

    执行输出:

    666
    func1

    此函数是完成登陆的功能,参数分别是...作用。
    :return: 返回值是登陆成功与否(True,False)

    这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了

     带装饰器的函数

    def wrapper(f):  # f = func1
        def inner(*args, **kwargs):  # 聚合
            # args (1,2,3)
            '''执行函数之前的相关操作'''
            ret = f(*args, **kwargs)  # 打散 1,2,3
            '''执行函数之后的相关操作'''
            return ret
    
        return inner
    
    
    @wrapper
    def func1():
        """
        此函数是完成登陆的功能,参数分别是...作用。
        :return: 返回值是登陆成功与否(True,False)
        """
        print(666)
        return True
    
    
    func1()
    print(func1.__name__)
    print(func1.__doc__)
    

     此函数是完成登陆的功能,参数分别是...作用。
    :return: 返回值是登陆成功与否(True,False)

    二, 带参数的装饰器

    #带参数的装饰器
    import time
    def timmer(*args,**kwargs):
        def wrapper(f):
            print(args,kwargs) #接收第一步的值
            def inner(*args,**kwargs):
                if flag:
                    start_time = time.time()
                    ret = f(*args,**kwargs)
                    time.sleep(0.3)
                    end_time = time.time()
                    print('此函数的执行效率{}'.format(end_time-start_time))
                else:
                    ret = f(*args,**kwargs)
                return ret
            return inner
        return wrapper
    flag = True
    @timmer(flag,2,3)  #两部:1.timmer(flag,2,3)相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)
    def func1(*args,**kwargs):
        return 666
    print(func1())
    

      

    执行输出:

    (True, 2, 3) {}
    此函数的执行效率0.300183

    666

    函数执行过程分析

    import time  #1.加载模块
    def timmer(*args,**kwargs): #2.读取timer这个函数变量名到内存中 #5.接收参数True 2, 3
        def wrapper(f):  #8.f = func1
            print(args,kwargs) #9.接收timmer函数的值True,2,3
            def inner(*args,**kwargs): #10. 加载变量 13.执行函数inner
                if flag:                #14.flag = True
                    start_time = time.time() #15获取当前时间
                    ret = f(*args,**kwargs)#16执行func1
                    time.sleep(0.3)         #19等待3秒
                    end_time = time.time()  #20获取当前时间
                    print('此函数的执行效率{}'.format(end_time-start_time)) #21打印差值
                else:
                    ret = f(*args,**kwargs)   #22返回给函数调用者func(1)
                return ret
            return inner #11.返回给函数调用者wrapper
        return wrapper  #7.返回给函数调用者timmer(flag,2,3)
    flag = True #3.加载变量
    @timmer(flag,2,3)  #4.执行函数timeer(flag,2,3)  17.执行函数func1   两步:1.timmer(flag,2,3)相当于执行wrapper 2.@wrapper 装饰器 func1 = wrapper(func1)
    def func1(*args,**kwargs):
        return 666      #返回给函数调用者
    print(func1()) #12.执行函数
    

      

    假定现在有100个函数,都加上了装饰器,增加了显示函数执行时间的功能,现在需要去掉!

    怎能办?一行行代码去删除吗?太low了。

    这个时候,直接在装饰器函数加一个参数即可。

    import time
    flag = False
    def wrapper(f):
        def inner(*args,**kwargs):
            if flag:
                start_time = time.time()
                ret = f(*args,**kwargs)
                time.sleep(0.3)
                end_time = time.time()
                print('此函数的执行效率%f' % (end_time-start_time))
            else:
                ret = f(*args, **kwargs)
            return ret
        return inner
     
    @wrapper
    def func1(*args,**kwargs):
        print(args,kwargs)
        return 666
    print(func1())
    

      

    现在需要关闭显示执行时间

    直接将flag改成false

    import time
    flag = False
    def wrapper(f):
        def inner(*args,**kwargs):
            if flag:
                start_time = time.time()
                ret = f(*args,**kwargs)
                time.sleep(0.3)
                end_time = time.time()
                print('此函数的执行效率%f' % (end_time-start_time))
            else:
                ret = f(*args, **kwargs)
            return ret
        return inner
     
    @wrapper
    def func1(*args,**kwargs):
        print(args,kwargs)
        return 666
    print(func1())
    

      

    执行输出:

    () {}
    666

    这样,所有调用的地方,就全部关闭了,非常方便

    写装饰器,一般嵌套3层就可以了

    实例二

    a = 5
    def func1():
        a += 1
        print(a)
    func1()
    

    执行报错

    这里函数对全局变量做了改变,是不允许操作的。

    函数内部可以引用全局变量,不能修改。如果要修改,必须要global一下

    a = 5
    def func1():
        global a
        a += 1
        print(a)
    func1()
    

      执行输出: 6

    三,多个装饰器,装饰一个函数

    def wrapper1(func):
        def inner1():
            print('wrapper1,before func')
            func()
            print('wrapper1 ,after func')
        return inner1
    
    def wrapper2(func):
        def inner2():
            print('wrapper2 ,before func')
            func()
            print('wrapper2,after func')
        return inner2
    
    @wrapper2
    @wrapper1
    def f():
        print('in f')
    f()
    

      

    执行输出:

    wrapper2 ,before func
    wrapper1 ,before func
    in f
    wrapper1 ,after func
    wrapper2 ,after func

    执行顺序如下图:

    多个装饰器,都是按照上图的顺序来的

    今日练习作业:

    1.写函数,返回一个扑克牌列表,里面有52项,每一项是一个元组

    例如:[('红心'2),('草花'2), …('黑桃''A')]
    #实例一:
    #思路:使用for循环先遍历出红心,黑桃,梅花,方块,再将使用for循环变量1-13个数字
    #步骤1:准备基础数据
    #颜色
    #扑克牌的4种颜色
    colour = ['黑桃♠','红心♥','梅花♣','方块♦']
    #牌面的值
    card = list[range(2,11) + ['A','J','Q','K']]
    

      

    #1.2使用for 循环遍历
    # 颜色
    colour = ['黑桃♠', '红心♥', '梅花♣', '方块♦']
    
    # 牌面的值
    card = list(range(2, 11)) + ['A', 'J', 'Q', 'K']
    #
    for i in card:
        for j in colour:
            print((j,i))
    

      执行输出:

    ('黑桃♠', 2)
    ('红心♥', 2)
    ('梅花♣', 2)

    1.3封装成函数

    def poker(*args, **kwargs):
        show_card = []
        for i in kwargs['card']:
            for j in kwargs['colour']:
                show_card.append((j, i))
        return show_card
    print(poker(colour=colour, card=card))
    

      

    执行输出:

    [('黑桃♠', 2), ('红心♥', 2), ('梅花♣', 2),...]

    2.写函数,传入n个数,返回字典{'max':最大值,'min':最小值}
    例如:min_max(2,5,7,8,4)
    返回:{'max':8,'min':2}

    2.1直接使用内置函数,可以得到最大值和最小值
    a = (1,2,3)
    b = {'k1':1,'k2':2}
    print(max(a))
    print(min(b.values()))
    

      

    执行输出:

    3
    1

    2.2封装成函数

    def min_max(*args,**kwargs):
        dic = {'max':None,'min':None}
        number = []
        #循环位置变量
        for i in args:    #这里是接收数据
            for j in i:   #这里是迭代数据,打散将每一个数字分成变量一个元素
                number.append(j)
        #循环关键字变量
        for k in kwargs.values():
            number.append(k)
    
        #最大值和最小值
        dic['max'] = max(number)
        dic['min'] = min(number)
    
        return dic
    
    print(min_max([2,3,4,5,6,9],a=8))
    

      执行后输出:

    {'max': 9, 'min': 2}

    3.写函数,专门计算图形的面积
    其中嵌套函数,计算圆的面积,正方形的面积和长方形的面积
    调用函数area('圆形',圆半径) 返回圆的面积
    调用函数area('正方形',边长) 返回正方形的面积
    调用函数area('长方形',长,宽) 返回长方形的面积
    def area():
    def 计算长方形面积():
    pass

    def 计算正方形面积():
    pass

    def 计算圆形面积():
    pass

    先找出公式


    长方形面积公式
    S = ab
    公式描述:公式中a,b分别为长方形的长和宽,S为长方形的面积。

    正方形面积公式
    S = a²
    公式描述:公式中a为正方形边长,S为正方形面积。

    圆的面积公式
    S = πr²
    公式描述:公式中r为圆的半径,π用3.14表示

    def area(*args,**kwargs):
        #计算长方形面积
        def rectangle(*args,**kwargs):
            #print(args)
            return args[0] * args[1]
     
        #计算正方形面积
        def square(*args,**kwargs):
            return args[0] ** 2
     
        #计算圆形面积
        def circular(*args,**kwargs):
            return 3.14 * (args[0] ** 2)
         
        #判断参数
        if args[0].strip() == '长方形':
            return rectangle(args[1],args[2])
        elif args[0].strip() == '正方形':
            return square(args[1])
        elif args[0].strip() == '圆形':
            return circular(args[1])
        else:
            return '参数不正确!'
     
    ret1 = area('长方形',3,4)
    ret2 = area('正方形',5)
    ret3 = area('圆形',6)
    print(ret1)
    print(ret2)
    print(ret3)
    

      

    def area(*args):
        # 判断参数
        if args[0] == '长方形':
            def 计算长方形面积():
                s = args[1] * args[2]
                return s
            return 计算长方形面积()
        elif args[0] == '正方形':
            def 计算正方形面积():
                s = args[1] ** 2
                return s
            return 计算正方形面积()
        elif args[0] == '圆形':
            def 计算圆形面积():
                s = 3.14 * (args[1] ** 2)
                return s
            return 计算圆形面积()
    
    print(area('长方形', 2, 3))
    print(area('正方形', 5))
    print(area('圆形', 6))
    

    给每个函数写一个记录日志的功能,
    功能要求:每一次调用函数之前,要将函数名称,时间节点记录到log的日志中。
    所需模块:
    import time
    struct_time = time.localtime()
    print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))

    #准备装饰器模版
    def wrapper(f):
        def inner(*args,**kwargs):
            '''函数装饰前'''
            ret = f(*args,**kwargs)
            '''函数装饰之后'''
            return ret
        return inner
    

      

    import time
    def wrapper(f):
        def inner(*args,**kwargs):
            '''被装饰函数之前'''
            ret = f(*args,**kwargs)
            '''被装饰函数之后'''
            struct_time = time.localtime()
            standard_time = time.localtime()
            print('函数名称:{} 时间节点:{}
    '.format(f.__name__, standard_time))
            return ret
        return inner
    @wrapper
    def func1():
        '''
        此函数是测试的
        :return:
        '''
        print(666)
        time.sleep(0.3)
        return True
    func1()
    

      加入些日志功能:

    import time
    def wrapper(f):
        def inner(*args,**kwargs):
            '''被装饰函数之前'''
            ret = f(*args,**kwargs)
            '''被装饰函数之后'''
            struct_time = time.localtime()
            standard_time = time.localtime()
            #写日志功能加入
            with open('function_log.txt', encoding='utf-8', mode='a+') as f1:
                f1.write('函数名称:{} 时间节点:{}
    '.format(f.__name__, standard_time))
            return ret
        return inner
    @wrapper
    def func1():
        '''
        此函数是测试的
        :return:
        '''
        print(666)
        time.sleep(0.3)
        return True
    func1()
    def wrapper(func):
        def inner(*args,**kwargs):
            struct_time = time.localtime()
            time_now = time.strftime("%Y-%m-%d %H:%M:%S", struct_time)
            with open('log', encoding='utf-8', mode='a') as f1:
                f1.write('在时间是%s,执行了%s函数
    ' % (time_now, func.__name__))
            ret = func(*args, **kwargs)
            '''函数执行之后操作'''
            return ret
        return inner
    
    @wrapper
    def func1():
        time.sleep(1)
        print(6666)
    @wrapper
    def func2():
        time.sleep(2)
        print(7777)
    func1()
    func2()
    

      

    写函数,传入一个参数n,返回n的阶乘
    例如: cal(7)

      

    def func3(n):
        count = 1
        for i in range(n,0,-1):
            count = count * i
        return count
    print(func3(7))
    

      执行后输出:

    5040

    编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),
    # 要求登录成功一次(三次机会),后续的函数都无需再输入用户名和密码

    准备雏形:

    def check_login(func): #检查登陆的装饰器
        def inner(*args,**kwargs):
            '''函数被装饰之前'''
            ret = func(*args,**kwargs)
            '''函数被装饰之后'''
            return ret
        return inner
     
    def index():
        print("welcome to index page")
         
    @check_login
    def home(): #用户主页
        print("welcome to home page")
     
    @check_login
    def bbs(): #bbs页面
        print("welcome to bbs page")
    

      

    #全局变量,用户状态
    dic = {
        'username':None,
        'status':False,
    }
    #错误次数
    i = 0
     
    def wrapper(func):
        def inner(*args, **kwargs):
            #判断登录状态是否为True
            if dic['status']:
                #执行被装饰行函数
                ret = func(*args, **kwargs)
                return ret
            else:
                #这里需要修改全局变量,要global一下
                global i
                while i < 3:
                    username = input('请输入用户名:').strip()
                    password = input('请输入密码:').strip()
                    with open('register_msg',encoding='utf-8') as f1:
                        for j in f1:
                            j_li = j.strip().split()  # ['张三','123']
                            if username == j_li[0] and password == j_li[1]:
                                #修改全局变量
                                dic['username'] = username
                                dic['status'] = True
                                ret = func(*args, **kwargs)
                                return ret
                        else:
                            print('账号或者密码错误,请重新输入%s机会' % (2-i))
                            i += 1
     
     
        return inner
     
     
    @wrapper
    def article():
        print('文章')
     
    @wrapper
    def diary():
        print('日记')
     
    @wrapper
    def comment():
        print('评论')
     
    @wrapper
    def file():
        print('文件')
     
    article()
    diary()
    comment()
    file()
    

      

     

  • 相关阅读:
    类和对象代码练习1
    搬迁MSSQL出现的问题
    QQ群空间是我见过最烂的系统
    导出表数据脚本的存储过程 [转自CSDN]
    plesk for Linux 没有默认首页的优先级别设置
    传说中的otag开源是假的。BS!!!!!
    FTP关闭mput上传确认
    刚装的vs2008不能生成silverlight,郁闷中
    怎么查域名反向解析是否成功
    现在的黑客太有才了。。。/不喜欢开防火墙的要小心
  • 原文地址:https://www.cnblogs.com/haowen980/p/8709844.html
Copyright © 2020-2023  润新知