装饰器
有参装饰器的实现
了解无参装饰器的实现原理后,我们可以再实现一个用来为被装饰对象添加认证功能的装饰器,实现的基本形式如下
def deco(func):
def wrapper(*args, **kwargs):
#编写基于文件的认证,认证通过则执行res=func(*args, **kwargs),并返回res
return wrapper
如果我们想提供多种不同的认证方式以供选择,单从wrapper函数的实现角度改写如下
def deco(func):
def wrapper(*args, **kwargs):
if driver == 'file':
print('基于文件认证通过')
res = func(*args, **kwargs)
return res
elif driver == 'mysql':
print('基于数据认证通过')
res = func(*args, **kwargs)
return res
print('...')
return wrapper
函数wrapper需要一个driver参数,而函数deco与wrapper的参数都有其特定的功能,不能用来接受其他类别的参数,可以在deco的外部再包一层函数auth,用来专门接受额外的参数,这样便保证了在auth函数内无论多少层都可以引用到
def auth(driver):
def deco(func):
def wrapper(*args, **kwargs):
if driver == 'file':
print('基于文件认证通过')
res = func(*args, **kwargs)
return res
elif driver == 'mysql':
print('基于数据认证通过')
res = func(*args, **kwargs)
return res
print('...')
return wrapper
return deco
@auth(driver='aaa')#这里因为我们传入的参数没有
#下面为该语法糖最后代表的内容
#--->@和auth(driver='aaa')--->而auth(driver='aaa')相当于是调用函数auth得到结果为deco函数的内存地址,即此时这里为@deco,这里我们也可以将其分开为@和deco--->而@的作用就是相当于将被装饰对象的函数名当作参数传入该函数,所以现在就为deco(index),而该函数的结果为wrapper,所以这里我们可以写为wrapper=deco(index),即wrapper=wrapper --->所以最后我们调用的函数其实是wrapper,但是装饰器的原则之一为不修改被装饰对象的调用方式,所以我们可以将wrapper函数对应的内存地址定义一个变量index=wrapper。
def index():
print('from index')
index()
#输出结果为
...
可以使用help(函数名)来查看函数的文档注释,本质就是查看函数的__doc__属性,但对于被装饰之后的函数,查看文档注释
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print('run time is %s'%(end_time - start_time))
return res
return wrapper
@timer
def home(name):
'''
home page function
:param name:str
:return:None
'''
time.sleep(5)
print('Welcome to the home pae', name)
print(help(home))
#输出结果为
Help on function wrapper in module __main__:
wrapper(*args, **kwargs)
None
Process finished with exit code 0
在被装饰之后home=wrapper,查看home.__name__也可以发现home的函数名确实是wrapper,想要保留原函数的文档和函数名属性,需要修正装饰器
def timer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
wrapper.__doc__=func.__doc__
wrapper.__name__=func.__name__
return wrapper
按照上述方式来实现保留原函数属性过于麻烦,functools模块下提供一个装饰器wraps专门用来帮我们实现这件事,用法如下
from functools import wraps
def timer(func):
@wraps(func)
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))
return res
return wrapper
迭代器
迭代器
迭代的工具。
迭代:
迭代指的是重复迭代,每一次迭代都是基于上一次的结果而来的。
迭代器:
迭代器指的是迭代取值的工具,它可以迭代取值。
- 如果想要知道python中迭代器是什么?必须先知道什么是可迭代对象?
- 可迭代对象: 所有的序列类型: str, list, tuple, dict, set, f
凡是内部有str.__iter__()方法的都是可迭代对象。
- 获取迭代器:
通过可迭代对象.__iter__(), 得到的返回值就是 “迭代器对象”。
迭代器是迭代取值的工具,作用是迭代取值。
- 如何迭代取值:
迭代器对象.__next__() # “每一次执行”,都会从迭代器对象中取出一个值
- 总结: 可迭代对象 VS 迭代器对象:
- 获取可迭代对象: 定义序列类型(str, list, set, tuple, dict, f)
- 特点:
内置有__iter__()
- 获取迭代器对象: 通过可迭代对象调用.__iter__()得到返回值
- 特点:
内置有__next__()
- 迭代器对象的优点:
- 优点:
1.不依赖于索引迭代取值。
2.节省内存空间。
- 缺点:
1.取指定某个值麻烦
2.每次取值都要从第一个值开始,无法同过索引取值。
for循环原理
语法: for i in 可迭代对象:
in: 可迭代对象 ----> 内部会自动调用.__iter__() ---> 迭代器对象
for line in list1:
# 迭代器对象.__next__()
- 迭代器本质上是一个可迭代对象
- 文件本质上既是迭代器对象,也是可迭代对象。
- 可迭代对象不一定是迭代器对象