目录
一、装饰器
二、迭代器
三、生成器
好麻,最近整理下Python学习笔记,把面试常问的几个装饰器、迭代器、生成器总结一下。
一、装饰器
装饰器定义:装饰器便于代码复用, 将函数作为参数传给装饰器函数, 拓展原来函数功能的一种函数。
装饰器作用:装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能(增强函数功能但是又不修改原函数, 抽离函数中与函数本身无关的功能进行复用)。
应用场景:插入日志、性能测试、事务处理、 Web权限校验、Cache等。
"""
1、无参函数装饰器
把@funA放到funA_test()函数的定义处,相当于执行了语句:funA_test = funA(funA_test)
"""
def funA(func):
print('1、装饰器函数 funA 增强 %s()' % func.__name__)
func()
@funA
def funA_test():
print('1、原函数 funA_test')
funA_test()
输出结果:
1、装饰器函数 funA 增强 funA_test()
1、原函数 funA_test
"""
2、不定长参数函数装饰器
wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
"""
def funB(func):
def wrapper(*args, **kwargs):
print('2、装饰器函数 funB 增强 %s()' % func.__name__)
func(*args, **kwargs)
return wrapper
@funB
def funB_test(x, y):
print('2、原函数 funB_test', x, '+', y, '=', x + y)
funB_test(2, 4)
输出结果:
2、装饰器函数 funB 增强 funB_test()
2、原函数 funB_test 2 + 4 = 6
二、迭代器
1、迭代器
迭代器定义:迭代器(Iterator)是访问集合内元素的一种方式,提供了一种遍历序列对象的方法。一个类(对象)只要含有__iter__、__next__两个方法,就将其称为迭代器。
迭代器作用:迭代器最核心的功能就是可以通过__next__方法的调用来返回下一个值。而这个值不是从已有的数据中读取的,而是通过程序按照一定的规则生成的。这也就意味着我们可以不再依赖一个现存的数据集合来存放数据,而是边用边生成,这样的好处就是可以节省大量的内存空间。
2、可迭代对象
一个对象只要含有__iter__方法,就将其称为可迭代对象。
Python可迭代对象有str(字符串)、list(列表)、tuple(元组)、dirt(字典)、set(集合)等。
3、总结
1.可迭代对象不一定是迭代器。
2.迭代器一定是可迭代对象。
3.容器类型(str list tuple dict set)是可迭代对象但不是迭代器。
# 定义一个迭代器
class IterDemo:
def __iter__(self):
self.a = 1
return self # __iter__ 方法返回了实例本身 self,也就是说返回了一个迭代器,所以 IterDemo 的实例 iterDemo 也是一个「可迭代对象」
def __next__(self):
x = self.a
self.a += 1
if self.a == 10:
raise StopIteration() # 异常用于标识迭代的完成,防止出现无限循环的情况
return x
def iter_demo():
iterDemo = IterDemo()
it = iter(iterDemo) # 创建迭代器对象
print('x = ', it.__next__()) # 输出迭代器的下一个元素
print('x = ', it.__next__()) # 输出迭代器的下一个元素
print('x = ', it.__next__()) # 输出迭代器的下一个元素
print('y = ', next(it)) # 输出迭代器的下一个元素
print('y = ', next(it)) # 输出迭代器的下一个元素
print('y = ', next(it)) # 输出迭代器的下一个元素
for i in it:
print('z = ', i)
输出结果:
x = 1
x = 2
x = 3
y = 4
y = 5
y = 6
z = 1
z = 2
z = 3
z = 4
z = 5
z = 6
z = 7
z = 8
# isinstance()检查对象是否是 类/子类 的实例
def isinstanc_demo():
lisTest = [1, 2, 3] # 可迭代的
lisTest1 = 1 # 不可迭代的
print("判断是否是可迭代的对象:", isinstance(lisTest, Iterable)) # Iterable(可迭代对象)
print("判断是否是迭代器:", isinstance(lisTest, Iterator)) # Iterator(迭代器)
print("判断是否是迭代器:", isinstance(IterDemo(), Iterator)) # Iterator(迭代器)
输出结果:
判断是否是可迭代的对象:True
判断是否是迭代器:False
判断是否是迭代器:True
def demo():
listTest = ['a', 'b', 'c']
# 迭代遍历
it = iter(listTest) # 创建迭代器对象
print('x= ', it.__next__())
print('y=', next(it))
for i in it:
print("z =", i) # 输出迭代器的下一个元素
# 正常遍历
for j in listTest:
print("j =", j)
输出结果:
x= a
y= b
z = c
j = a
j = b
j = c
三、生成器
生成器定义:一边循环一边计算的机制,称为生成器(generator)。生成器(generator)也是一种迭代器,在每次迭代时返回一个值,直到抛出 StopIteration 异常。
生成器作用:列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。如:仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
# 创建生成器方式1:把一个列表生成式的[]改成(),就创建了一个generator
# l是一个list,而g是一个generator
def demo():
l = [x * x for x in range(10)]
print(l)
g = (x * x for x in range(10))
print(g) # 打印的是一个对象
print('x =', next(g))
print('x =', next(g))
print('x =', next(g))
print('y =', g.__next__())
print('y =', g.__next__())
print('y =', g.__next__())
for i in g:
print('z =', i)
g.close() # 关闭生成器
输出结果:
x = 0
x = 1
x = 4
y = 9
y = 16
y = 25
z = 36
z = 49
z = 64
z = 81
# 创建生成器方式2:yield
def yield_demo():
for i in range(10):
yield i
def yield_demo_test():
yie = yield_demo()
print('x =', next(yie))
print('x =', next(yie))
print('x =', next(yie))
print('y =', yie.__next__())
print('y =', yie.__next__())
print('y =', yie.__next__())
for i in yie:
print('z =', i)
输出结果:
x = 0
x = 1
x = 2
y = 3
y = 4
y = 5
z = 6
z = 7
z = 8
z = 9
相关代码已经放到 https://gitee.com/weimenghua/Learn-Python/tree/master/base,decorator_demo.py 、generator_demo.py 、iteration_demo.py。
总结:因为在自动化测试中,装饰器是非常重要的,它可以帮助我们将一个公共部分抽象出来,有点类似于切面编程(AOP),可以让开发者更专注于业务逻辑。迭代器和生成器可以节省大量内存空间,但这块我还没有深刻的理解。
https://www.processon.com/view/link/615eae81e0b34d06f3dcdf4b