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())
原文地址:https://www.cnblogs.com/pythonblogs/p/11122968.html