最近写项目时,遇到类嵌套和yield的混合使用,觉得比较典型,正好借此加深对迭代器和生成器的理解。
代码
代码抽象如下:
from types import FunctionType
class RowItems(object):
def __init__(self,option,x1,x2,x3):
self.option = option
self.x1 = x1
self.x2 = x2
self.x3 = x3
def __iter__(self):
yield 1
yield 11
yield 111
yield 1111
yield 11111
yield 111111
yield 1111111
class Option(object):
def __init__(self,name_or_func,status):
self.name_or_func = name_or_func
self.status = status
def is_func(self):
if isinstance(self.name_or_func,FunctionType):
return True
def func(configs):
for option in configs:
if option.is_func():
data_list = None
else:
data_list = RowItems(option,11,22,33)
yield data_list
list_filter_config = [
Option('name',True),
Option('email',True),
]
result = func(list_filter_config)
for v in result:
for j in v:
print(j)
打印结果如下:
1
11
111
1111
11111
111111
1111111
1
11
111
1111
11111
111111
1111111
知识准备:
关于迭代器和生成器的基本知识,可以参考 http://blog.csdn.net/ayhan_huang/article/details/73374894
我们知道,可迭代对象都具有__iter__
方法,因此只要在类中定义该方法,那么其实例化对象就是可迭代对象,就可以被for循环,比如:
class Foo(object):
def __iter__(self):
return iter([1,2,3])
obj = Foo()
for i in obj:
print(i)
""" 打印结果
1
2
3
"""
而如果一个函数中有yield,那么执行函数就会拿到一个生成器(生成器就是迭代器)。
流程分析:
下面我们具体看一下本文开头给出的那段代码的执行流程
- list_filter_config 中拿到两个实例化对象,假设为: A & B
- result = func(list_filter_config),未执行func具逻辑,直接拿到一个生成器对象,假设为F_gen
- for v in result: 执行生成器,F_gen
- 执行func :
- 循环list_filter_config第一个元素 A
- 实例化RowItems对象,得到可迭代对象,假设为:A_iter
- func:yield A_iter 返回 A_iter
- 回到for v in result: A_iter, F_gen
- for j in v: 迭代A_iter:每打印一行,回到for j in v,触发A_iter继续迭代
- 迭代A_iter 完成,打印出第一个金字塔
- 回到for v in result: F_gen
- 执行func :
- 循环list_filter_config第二个元素 B
- 实例化RowItems对象,得到可迭代对象,假设为:B_iter
- func:yield B_iter 返回 B_iter
- 回到for v in result: B_iter
- for j in v: 迭代B_iter:每打印一行,回到for j in v,触发B_iter继续迭代
- 迭代B_iter完成,打印出第二个金字塔