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()

  

 

原文地址:https://www.cnblogs.com/haowen980/p/8709844.html