装饰器
有参装饰器的实现
了解无参装饰器的实现原理后, 我们可以再实现一个用来为被装饰对象添加认证功能的装饰器, 实现的基本形式如下
- 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__()
- 迭代器本质上是一个可迭代对象
- 文件本质上既是迭代器对象, 也是可迭代对象.
- 可迭代对象不一定是迭代器对象
来源: http://www.bubuko.com/infodetail-3295375.html