zoukankan      html  css  js  c++  java
  • 12..装饰器

    def wrapper(f):
    	def inner(*args,**kwargs):
    		'被装饰之前的函数'
    

    1.开发封闭原则

    软件面世时,不可能把所有的功能都设计好,当前的未来一两年功能给你上线,定期更新迭代。对于软件之前的写的源代码一般都不会修改,对函数里面的代码以及函数的调用方式。

    开放原则:在源码不改变的情况下,增加一些额外的功能。

    封闭原则:不要改变源码

    python中装饰器:完美的诠释了的开放封闭原则。

    装饰器就是一个函数: 他要装饰一个函数,在不改变原函数的源码以及调用方式的前提下,给其增加一个额外的功能。

    27.1 初识装饰器

    1 李业,在一家xx科技有限公司工作,主管安排了一个任务,写一个代码测试怼怼哥写的函数的执行效率

    import time
    def index():
        time.sleep(2)
        print('欢迎访问博客园首页')
    
    
    print(time.time())
    start_time = time.time()
    index()
    end_time = time.time()
    print(f'此函数的执行效率{end_time-start_time}')
    
    2. 主管让你测试小邓,李大象,重复代码太多。
    
    def func1():
        time.sleep(2)
        print('欢迎访问日记首页')
    
    
    def func2():
        time.sleep(1)
        print('欢迎访问评论首页')
    
    start_time = time.time()
    func1()
    end_time = time.time()
    print(f'此函数的执行效率{end_time-start_time}')
    
    start_time = time.time()
    func2()
    end_time = time.time()
    print(f'此函数的执行效率{end_time-start_time}')
    
    3.  整合到函数中
    
    def func1():
        time.sleep(2)
        print('欢迎访问日记首页')
    
    
    def func2():
        time.sleep(1)
        print('欢迎访问评论首页')
    
    
    def test_time(x):
        start_time = time.time()
        x()
        end_time = time.time()
        print(f'此函数的执行效率{end_time-start_time}')
    
    test_time(func1)
    test_time(func2)
    
    
    4. 怼怼哥这个函数在实际项目中被500执行,主管要求:在被执行此函数时,
    同时要测试一下被执行函数的效率。
    
    
    def index():
        time.sleep(2)
        print('欢迎访问博客园首页')
    
    # index()
    def test_time(x):
        start_time = time.time()
        x()
        end_time = time.time()
        print(f'此函数的执行效率{end_time-start_time}')
    
    test_time(index)
    
    版本4的问题: 开放原则满足了,封闭原则:不改变原函数的源码,以及调用方式。
    违反了封闭原则:改变了函数的调用方式。
    
    
    版本5: 不能改变原函数的调用方式(闭包):
    
    
    def index():
        time.sleep(2)
        print('欢迎访问博客园首页')
    
    index()
    
    def func1():
        time.sleep(2)
        print('欢迎访问日记首页')
    
    def test_time(x):  # x = index
        def inner():
            start_time = time.time()
            x()
            end_time = time.time()
            print(f'此函数的执行效率{end_time-start_time}')
        return inner
    
    index = test_time(index)
    index()
    
    

    语法糖@加上装饰器函数的名

    def test_time(x):  # x = index
        def inner():
            start_time = time.time()
            x()
            end_time = time.time()
            print(f'此函数的执行效率{end_time-start_time}')
        return inner
    
    
    # @test_time  # index = test_time(index)
    def index():
        time.sleep(2)
        print('欢迎访问博客园首页')
    
    index = test_time(index)
    index()
    
    def func1():
        time.sleep(2)
        print('欢迎访问日记首页')
    
    @test_time
    def func2():
        time.sleep(1)
        print('欢迎访问评论首页')
    
    func2 = test_time(func2)
    func3 = test_time(func3)
    func2()
    
    1561365990840
    1561366007232
    z
    27.2 被装饰函数带返回值
    def test_time(x):  # x = index
        def inner():
            start_time = time.time()
            ret = x()
            # print(F'ret: {ret}')
            end_time = time.time()
            print(f'此函数的执行效率{end_time-start_time}')
            return ret
        return inner
    
    
    @test_time  # index = test_time(index)
    def index():
        time.sleep(0.5)
        print('欢迎访问博客园首页')
        return True
    
    print(index())  # inner()
    
    27.3 被装饰函数带参数
    无论加不加装饰器,你的实参'太白金星'应该传给形参n,。
    但版本6不能实现传参,index('太白金星') ==  inner('太白金星')
    import time
    struct_time = time.localtime()
    # print(time.strftime("%Y-%m-%d %H:%M:%S",struct_time))
    
    def test_time(x):# x = index
    	def inner(*args,**kwargs):
    		#函数的定义:* **聚合
    		# args = ('苹果')
    		# args =(1,3)
    		start_time = time.time()
    		ret = x(*args,**kwargs)
    		#函数的执行:* **打散
    		# ret = x(*('苹果')) ==x('苹果',)
    		# ret = x(*(1,3)) == x(1,3)
    		#print(f'ret:{ret}')
    		end_time = time.time()
    		print(f'此函数的效率{end_time-start_time}')
    		return ret
    	return inner
    @test_time  # index = test_time(index)
    def index(n):
    	time.sleep(0.5)
    	print(f'欢迎{n}访问博客园首页')
    	return True
    @test_time  # index = test_time(index)
    def func2(a,b):
    	time.sleep(0.5)
    	print(f'最终结果:{a+b}')
    	return a + b
    
    
    print(index('苹果'))  # inner('苹果')
    print(func2(1,3)) # == inner(1,3)
    
    27.4 标准版装饰器
    def warpper(f):
    	def inner(*args,**kwargs):
    		'''被装饰函数之前的操作'''
            # print(657)
            ret = f(*args,**kwargs)
            '''被装饰函数之后的操作'''
            # print('执行完毕了')
            return ret
        return inner
    
    @warpper
    def func():
        print(111)
    func()
    

    装饰器的应用:在不改变原函数的源码以及调用方式前提下,为其增加额外的功能。登陆认证,打印日志等。

    def wrapper(f):
    	def inner(*args,**kwargs):
    		ret = f(*args,**kwargs)
    		return ret
    	return inner
    
    27.5 模拟博客园登录
    dic_status = {
    	'username':None,
    	'status':False
    }
    #方法一:
    # def get_pwd():
    #   dic = {}
    # 	with open('qq',encoding='utf-8')as f1:
    # 		for i in f1:
    # 			line = i.strip().split("|")
    # 			dic[line[0]] = line[1]
    #       return dic
    # 方法二:
    def get_pwd():
    	dic = {}
    	with open('qq',encoding='utf-8')as f1:
    		for i in f1:
    			user,pwd = i.strip().split("|")
    			dic[user] = pwd
    		return dic
    # 方法三:
    # def get_pwd():
    # 	with open('qq', encoding='utf-8')as f1:
    # 		return {i.strip().split('|')[0]:i.strip().split('|')[1] for i in f1}#字典推导式
    def login(dic_pwd):
    	dic1 = dic_pwd()
    	count = 0
    	while count < 3:
    		username = input('请输入用户名').strip()
    		password = input('请输入密码').strip()
    		# if username in dic1 and password == dic1[username]:
    		if dic1.get(username) == password:
    			print('登录成功')
    			dic_status['username'] = username
    			dic_status['status'] = True
    			return True
    		else:
    			print('用户名或密码错误')
    		count += 1
    	return False
    def auth(f):
    	def inner(*args,**kwargs):
    		'''要进行登陆认证:
    			有两个分支:
    				1,如果之前登陆成功了,直接访问。
    				2,如果这是之前没有登陆过,先进行三次登陆。
    		'''
    		if dic_status['status']:
    			ret = f(*args,**kwargs)
    			return ret
    		else:
    			if login(get_pwd):
    				ret = f(*args, **kwargs)
    				return ret
    	return inner
    @auth
    def article():
    	print('欢迎访问文章页面')
    
    
    @auth
    def diary():
    	print('欢迎访问日记页面')
    
    
    @auth
    def comment():
    	print('欢迎访问评论页面')
    
    
    article()
    diary()
    comment()
    
    
    27.6 装饰器的执行步骤
    def wrapper(f):  # 1,执行wrapper函数,并且将func函数名 传给 变量f
        def inner(*args,**kwargs):
            print(111)  # 5,打印111
            ret = f(*args,**kwargs)  # 6,执行真正的func函数
            print(222)  # 8, 打印222
            return ret
        return inner
    
    @wrapper  # func = wrapper(func)  # 2,将inner函数名给了重新定义的变量 func = inner
    def func():
        print(333)  # 7,打印333
    
    print(444)  # 3, 打印 444
    func()  # 4,inner() 执行inner函数
    print(555)  # 9,打印555
    
    def func():
        print(666)
    
    func = inner
    print(func)
    
    
    27.7 带参数的装饰器
    def wrapper(f):
        def inner(*args,**kwargs):
            if f.__name__ == 'qq': #通过函数名
    
                ret = f(*args,**kwargs)
                return ret
            else:
    			pass
    
    	return inner
    
    def wrapper_out(n,*args,sex='男',):
        def wrapper(f):  # f
            def inner(*args,**kwargs):
                ret = f(*args,**kwargs)  # func1()
                return ret
            return inner
        return wrapper
    def func1():
        print('in func1')
    func = wrapper_out(1)  # wrapper函数名
    ly = func(func1)  # wrapper(func1) = inner
    ly()  # inner()
    

    从两个文件读取账号密码,登录

    方法一:代码多,重复

    def wrapper_out(n):
        def wrapper(f):
            def inner(*args,**kwargs):
            	if n == 'qq':
                    username = input('请输入用户名:').strip()
                    password = input('请输入密码:').strip()
                    with open('qq',encoding='utf-8') as f1:
                        for line in f1:
                            user,pwd = line.strip().split('|')
                            if username == user and password == pwd:
                                print('登陆成功')
                                ret = f(*args,**kwargs)
                                return ret
                        return False
                elif n == 'tiktok':
                    username = input('请输入用户名:').strip()
                    password = input('请输入密码:').strip()
                    with open('tiktok', encoding='utf-8') as f1:
                        for line in f1:
                            user, pwd = line.strip().split('|')
                            if username == user and password == pwd:
                                print('登陆成功')
                                ret = f(*args, **kwargs)
                                return ret
                        return False	
          
            return inner
        return wrapper
    @wrapper_out('qq')
    def qq():
        print('成功访问qq')
    
    
    @wrapper_out('tiktok')
    def tiktok():
        print('成功访问抖音')
    
    qq()
    tiktok()
    

    方法二:直接判断n 传进来的路径。

    def wrapper_out(n):
        def wrapper(f):
            def inner(*args,**kwargs):
              username = input('请输入用户名:').strip()
              password = input('请输入密码:').strip()
                with open(n,encoding='utf-8') as f1:
                    for line in f1:
                        user,pwd = line.strip().split('|')
                        if username == user and password == pwd:
                            print('登陆成功')
                            ret = f(*args,**kwargs)
                            return ret
                    return False
            return inner
        return wrapper
    @wrapper_out('qq')
    def qq():
        print('成功访问qq')
    
    
    @wrapper_out('tiktok')
    def tiktok():
        print('成功访问抖音')
    
    qq()
    tiktok()
    
    @wrapper_out('qq')
    def qq():
        print('成功访问qq')
    qq()
    看到带参数的装饰器分两步执行:
    '''
    @wrapper_out('腾讯')
        1. 执行wrapper_out('腾讯') 这个函数,把相应的参数'腾讯' 传给 n,并且得到返回值 wrapper函数名。
        2. 将@与wrapper结合,得到我们之前熟悉的标准版的装饰器按照装饰器的执行流程执行。
    '''
    """
    

    方法三:qq 抖音两个文件取账号密码,带参数的装饰器

    status = {'flag':False,'username':None}
    def get_pwd(path):
    	dic = {}
    	with open(path, encoding='utf-8')as f1:
    		for i in f1:
    			line = i.strip().split('|')
    			dic[line[0]] = line[1]
    		return dic
    def login(dic_pwd):
    	dic1 = dic_pwd
    	username = input('请输入用户名:')
    	pwd = input('请输入密码:')
    	if  username in dic1 and dic1[username]==pwd:
    		print('登录成功')
    		status['flag'] = True
    		status['username'] = username
    		return True
    	else:
    		return False
    def wrapper_out(n):
    	def wrapper(f):
    		def inner(*args,**kwargs):
    			if login(get_pwd(n)):
    				ret = f(*args,**kwargs)
    				return ret
    		return inner
    	return wrapper
    @wrapper_out('qq')
    def qq():
    	print('成功访问qq')
    
    @wrapper_out('douyin')
    def ti():
    	print('成功访问抖音')
    qq()
    ti()
    
    27.8 多个装饰器装饰一个函数
    def wrapper1(func1):  # func1 = f原函数
        def inner1():
            print('wrapper1 ,before func')  # 2
            func1()
            print('wrapper1 ,after func')  # 4
        return inner1
    
    def wrapper2(func2):  # func2 == inner1
        def inner2():
            print('wrapper2 ,before func')  # 1
            func2()  # inner1
            print('wrapper2 ,after func')  # 5
        return inner2
    
    
    @wrapper2  # f = wrapper2(f) 里面的f == inner1  外面的f == inner2
    @wrapper1  # f = wrapper1(f) 里面的f == func1  外面的 f == inner1
    def f():
        print('in f')  # 3
    
    f()  # inner2()
    

    1561451265118

    1561451291856

    def wrapper1(func):
        def inner1():
            print('wrapper1 ,before func')
            ret = func()
            print('wrapper1 ,after func')
            return ret
        return inner1
    
    def wrapper2(func):
        def inner2():
            print('wrapper2 ,before func')
            ret = func()
            print('wrapper2 ,after func')
            return ret
        return inner2
    
    def wrapper3(func):
        def inner3():
            print('wrapper3 ,before func')
            ret = func()
            print('wrapper3 ,after func')
            return ret
        return inner3
    
    @wrapper3
    @wrapper2
    @wrapper1
    def f():
        print('in f')
        return '哈哈哈'
    
    print(f())
    
  • 相关阅读:
    关于C51的中断函数要注意的几个问题
    WORD文档中插入页码的问题
    【转载】vim复制时的缩进
    【转载】在Linux下,一个文件也有三种时间,分别是:访问时间、修改时间、状态改动时间
    【转载】LINUX上MYSQL优化三板斧
    【转载】小结一下linux 2.6内核的四种IO调度算法
    【转载】linux挂载mount参数优化
    【转载】ipcs与Linux共享内存
    【转载】Linux下的IO监控与分析
    【转载】netstat--查看服务器[有效]连接数--统计端口并发数--access.log分析
  • 原文地址:https://www.cnblogs.com/pythonblogs/p/11122968.html
Copyright © 2011-2022 走看看