itertion
就是迭代,一个接一个(one after another),是一个通用的概念,比如一个循环遍历某个数组。
iterable
这个是可迭代对象,属于python的名词,范围也很广,可重复迭代,满足如下其中之一的都是iterable:
- 可以for循环: for i in iterable
- 可以按index索引的对象,也就是定义了getitem方法,比如list,str;
- 定义了iter方法。可以随意返回。
- 可以调用iter(obj)的对象,并且返回一个iterator
iterator
迭代器对象,也属于python的名词,只能迭代一次。需要满足如下的迭代器协议
- 定义了iter方法,但是必须返回自身
- 定义了next方法,在python3.x是next。用来返回下一个值,并且当没有数据了,抛出StopIteration可以保持当前的状态
generator
任何使用yield的函数都称之为生成器。
迭代器的功能可以使用列表代替,但如果有很多值,列表就会占用太多的内存,而如果有可以一个接一个地计算值的函数,那么就可以在使用时采用计算一个值时获取一个值,占用更少内存。
- 构造一个迭代器只需要在自定义的类中实现两个方法:
__iter__
和__next__
。
__iter__
:返回迭代器对象自身。为了允许容器和迭代器被用于for和in语句中,必须实现该方法。__next__
:返回容器的下一个条目。如果没有更多的条目,抛出StopIteration异常- 需要注意的是在迭代器中next方法是return下一个元素的值,不像下面介绍的生成器yield一个元素
s = "alan"
si = iter(s)
l = [1, 2]
li = iter(l)
print(si) #
print(li) #
print(si.__iter__()) # 可迭代对象有__iter__()方法
print(si.__next__()) # a 拥有__next__方法
print(si.__next__()) # l
print(si.__iter__() is si) # True __iter__返回自己
# 自定义迭代器
class DataIter(object):
def __init__(self, *args):
self.data = list(args)
self.ind = 0
def __iter__(self): # 返回自身
return self
def __next__(self): # 返回数据
if self.ind == len(self.data):
raise StopIteration
else:
data = self.data[self.ind]
self.ind += 1
return data
obj = DataIter(1, 2, 3)
print(obj.__iter__()) # <__main__.DataIter object at 0x10f3cfe20>
print(obj.__next__()) # 1
print(obj.__next__()) # 2
print(obj.__next__()) # 3
# print(obj.__next__()) # 报错
"""
next函数只能向前取数据,一次取一个,不能重复取数据,那这个可不可以解决呢?
iterator只能迭代一次,但是iterable对象则没有这个限制
可以把iterator从数据中分离出来,分别定义一个iterable与iterator如下
"""
class Data(object): # 只是iterable:可迭代对象而不iterator:迭代器
def __init__(self, *args):
self.data = list(args)
def __iter__(self): # 并没有返回自身
return DataIterator(self)
class DataIterator(object): # iterator: 迭代器
def __init__(self, data):
self.data = data.data
self.ind = 0
def __iter__(self):
return self
def __next__(self):
if self.ind == len(self.data):
raise StopIteration
else:
data = self.data[self.ind]
self.ind += 1
return data
if __name__ == '__main__':
d = Data(1, 2, 3)
for x in d:
print(x)
for x in d:
print(x)
"""
1
2
3
1
2
3
"""
在Python中,一边迭代(循环)一边计算的机制,称为生成器。生成器能够迭代的关键是因为它有一个
__next__
方法。生成器就是一个返回迭代器的函数,与普通函数的区别是生成器包含yield语句,更简单点理解生成器就是一个迭代器。
# 三元表达式构造的生成器
a = (x for x in range(10000000))
print(next(a)) # 0
print(next(a)) # 1
print(a.__next__()) # 2
print(a.__iter__() is a) # True
print(iter(a) is a) # True
# yield关键字构造的生成器
a = [x for x in range(3)]
type(a) # list
a = (x for x in range(3))
type(a) # generator
import time
tic = time.time()
a = sum([x for x in range(10000000)])
toc = time.time()
print(toc - tic) # 2.3462159633636475
tic = time.time()
a = sum((x for x in range(10000000)))
toc = time.time()
print(toc - tic) # 0.847653865814209
def num():
print('开始执行')
for i in range(5):
yield i
print('继续执行')
mygen = num()
print(type(mygen)) #
一般我们不会用
next()
来获取下一个返回值,而是直接使用for
循环来迭代。
# next迭代获取
next(mygen)
# for循环获取
for step in mygen:
print(step)
def get_table(**kwargs):
engine = db_client.datacenter_orm.get_engine()
schema = kwargs.get('schema')
table_name = kwargs.get('table')
metadata = MetaData(bind=engine)
try:
table_item = Table(table_name, metadata, autoload=True, schema=schema)
except:
table_item = Table(table_name.lower(), metadata, autoload=True, schema=schema)
return table_item
def get_batch(table_model, task_info):
sort_field = task_info.get("sort_field", "")
common_field = task_info.get("common_field", [])
batch_size = task_info.get("batch_size", 1000)
fields = []
for f in common_field:
fields.append(get_model_field(table_model, f))
fields = tuple(fields)
limit_offset = 0
while True:
session = db_client.datacenter_orm.new_session()
items = session.query(*fields) \
.order_by(get_model_field(table_model, sort_field)) \
.offset(limit_offset).limit(batch_size).all()
item_dict = [row2dict(item) for item in items]
session.close()
yield item_dict
if len(item_dict) < batch_size:
break
limit_offset += len(item_dict)
yield []
task_info = {
"common_field": ["id", "name"],
"sort_field": "id"
}
y_data = get_batch(get_table(self.conf), task_info)
for data_column in y_data:
...