本节内容:
1、函数之装饰器
2、面向对象之单例模式
一、函数之装饰器(闭包的运用)
装饰器本质上就是一个python函数,一个闭包函数的运用,
他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。
装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。
1、装饰器的形成过程
现在有一个需求,要测试一个函数的执行时间,在不改变这个函数的执行情况下:
fe1:简单版的装饰器
简单版的装饰器
# 增加一个函数 测试其他函数执行效率的功能,但是尽量不要改变原函数的执行方式.
import time
def func(): # 被装饰的函数
time.sleep(0.2)
print('10万行代码')
def func1():
time.sleep(0.2)
print('11万行代码')
# func = 666
# func()
def timmer(f): # func函数名 = f
def inner():
start_time = time.time()
f()
end_time = time.time()
print('此函数的执行效率为%s' % (end_time - start_time))
return inner
func = timmer(func) # inner
func() # inner()
func1 = timmer(func1)
func1()
# 上个版本不行,每次执行被测试时间的函数时,必须要加一行代码.
# 怎么解决,看下面的语法糖
Python
fe2:装饰器—-语法糖
装饰器:在不改变原函数的执行(代码机构基础上,给原函数增加一些额外的功能,登录验证,打印日志,测试效率等等.
语法糖,就是python里面封装好的func = timmer(func),你直接调用就行,不用再自己写了
装饰器的语法糖运用
import time
def timmer(f): # func函数名 = f
def inner(x,y):
start_time = time.time()
f(x,y)
end_time = time.time()
print('此函数的执行效率为%s' % (end_time - start_time))
return inner
@timmer # func = timmer(func)
def func(x,y):
time.sleep(0.2)
print(x + y)
# 语法糖 @
# @timmer # func1 = timmer(func1)
# def func1():
# print(666)
func(10,20) # inner(10,20)
# func1()
Python
fe3:被装饰函数带参数,这时用无敌传参(*args, **kwargs)
无敌传参解决被装饰函数带参数
import time
def timmer(f): # func函数名 = f
def inner(*args, **kwargs): # 传参,聚合
# args = (10,20)
start_time = time.time()
f(*args,**kwargs) # 被装饰函数的执行 * 打散 10 , 20 f(10,20)
end_time = time.time()
print('此函数的执行效率为%s' % (end_time - start_time))
return inner
@timmer # func = timmer(func) func2 = timmer(func2) 这时的func2已经不是被装饰函数了
def func(x,y):
time.sleep(0.2)
print(x + y)
@timmer
def func2(x,y,z,w):
print(x,y,z,w)
# func(10, 20) # inner(10,20)
func2(1,2,3,w=4) # 这里的参数被inner的f接收了,f就是语法糖传参的被装饰函数名
Python
fe4: 标准的装饰器, 被装饰的函数带参数,带返回值
标准的装饰器
import time
def timmer(f): # func函数名 = f
def inner(*args, **kwargs): # 接收被装饰函数的参数
start_time = time.time()
ret = f(*args,**kwargs) # 接收被装饰函数执行之后的返回值
end_time = time.time()
print('此函数的执行效率为%s' % (end_time - start_time))
return ret # 将返回值,返回给调用者
return inner
@timmer # func = timmer(func)
def func(x,y,z,e):
time.sleep(0.2)
return x + y + z + e
ret1 = func(10, 30, 3, 4) # inner(10, 30)
print(ret1)
Python
2、面试题(手写一个装饰器)
def wrapper(f):
def inner(*args, **kwargs):
'''被装饰函数执行之前的操作'''
ret = f(*args, **kwargs)
"""被装饰函数执行之后的操作"""
return ret
return inner
Python
3、装饰器的应用: 登录验证.
需求:登陆后可以在各个页面切换
名字
dic_status = {
'username': None,
'status': False,
}
def login(f):
def inner(*args, **kwargs):
'''被装饰函数执行之前的操作'''
if dic_status['status'] :
ret = f(*args, **kwargs)
return ret
else:
username = input('请输入用户名').strip()
password = input('请输入密码').strip()
with open('register', encoding='utf-8') as f1:
for line in f1:
user, pwd = line.split('|')
if username == user.strip() and password == pwd.strip():
dic_status['username'] = username
dic_status['status'] = True
print('登录成功,正在跳转...')
ret = f(*args, **kwargs)
return ret
else:
print('登录失败...')
return inner
@login
def article():
print('欢迎登录文章页面')
@login
def diary():
print('欢迎登录日记页面')
@login
def comment():
print('欢迎登录评论页面')
dic = {
1: article,
2: diary,
3: comment,
}
while 1:
num = input('欢迎访问博客园,请选择:
1文章页面
2 日记页面
3 评论页面').strip()
if num.isdigit():
dic[int(num)]()
else:
print('重新输入..')
# 还需写一个register的文件来放用户信息,进行登录验证
Python
4、带参数的装饰器
带参数的装饰器
import time
def timmer(flag): # 这个函数的作用是,将参数传给装饰器函数
def wrapper(f): # 这个函数的作用是:将被装饰函数作为参数传入
def inner(*args, **kwargs): # 传入被装饰函数的参数,传参
if flag: # 通过这个状态来,控制是否执行装饰器函数
start_time = time.time()
ret = f(*args, **kwargs)
end_time = time.time()
print('执行时间%s' % (end_time-start_time))
return ret
else:
ret = f(*args, **kwargs)
return ret
return inner
return wrapper
flag1 = False
@timmer(flag1) # 第一步,将@ 与后面 分开,只是单纯的执行timmer(flag1)函数 第二部 将@ 与 wrapper相结合,形成装饰器
def func1():
time.sleep(0.3)
print('in func1')
func1()
Python
5、多个装饰器 装饰一个函数
多个装饰器 装饰一个函数
def wrapper1(func): # func == f 函数名
def inner1():
print('wrapper1 ,before func') # 2
func()
print('wrapper1 ,after func') # 4
return inner1
def wrapper2(func): # func == inner1
def inner2():
print('wrapper2 ,before func') # 1
func()
print('wrapper2 ,after func') # 5
return inner2
# 就近原则 先将近的传给装饰器函数,多个装饰器的话,逐层上传
@wrapper2 # f = wrapper2(f) 里面f == inner1 外面的f == inner2
@wrapper1 # f = wrapper1(f) 里面的f == 函数名f 外面的f == inner1
def f():
print('in f') # 3
f() # inner2()
Python
二、面向对象之单例模式
就是只能实例化一个对象,不管创建多少个对象,都是指向同一个内存地址
例如:多个py文件在引入同一个模块,如果没有设置
1、单例模式代码示例
class A:
__instance = None # 定义一个私有变量,
def __new__(cls, *args, **kwargs): # 通过重写父类的__new__方法,来控制指向第一个实例化对象的地址
if A.__instance is None: # 通过私有变量来控制指向第一个实例化对象的(同一个)的地址
obj = object.__new__(cls) # 如果是第一次实例化对象,就创建对象,
A.__instance = obj
return A.__instance # 如果不是第一次,就直接指向第一次对象的内存地址,不再创建对象
obj1 = A()
obj2 = A()
obj3 = A()
obj4 = A()
print(obj1) # 都指向同一个内存地址
print(obj2)
print(obj3)
print(obj4)