lst = [1, 2, 3, 4]
data_set = set([4, 5, 6, 7])
获取迭代器
lst_iter = iter(lst)
set_iter = iter(data_set)
遍历迭代器
def iter_it(iter_obj):
while True:
try:
data = next(iter_obj)
print(data)
except:
break
iter_it(lst_iter)
print('*'*20)
iter_it(set_iter)
1 2 3 4 ******************** 4 5 6 7
没有使用 for
循环,而是通过 iter
函数获取列表和集合的迭代器,通过 next
函数获取迭代器里的下一个元素,
for
循环内部所做的事情与上面的代码所表达的逻辑几乎是相同的。
列表和集合,底层的实现是不相同的,但可以用相同的方法对他们进行遍历,这中间就是迭代器模式在起作用, 设想,如果因为底层实现不同,遍历的方式就不同,那对于写代码来说将是一场灾难。
如果集合底层实现用的是树,就需要考虑用深度优先遍历或是广度优先遍历,如果底层实现的方法是 hashtable
,
那么就需要考虑像遍历列表一样进行遍历,底层实现的差异所造成的遍历方式的不同都被迭代器模式所屏蔽掉了,
只需要获取到迭代器就能够遍历集合,无需关心底层的具体实现, 这就是迭代器模式的精髓。
掌握了迭代器模式的精髓,那么只要能够在代码里体现这种原则,目的,就可以认为是实现了迭代器模式, 模式不是标准,不是非得怎样才行,看到的文章里设定了各种名词以及代码里的所展示出的固定格式, 都只是为了更容易去用代码阐述某种模式,但不要被限定在代码的格式中,去努力理解一种模式的设计初衷和目的。
编写遍历对象属性的迭代器
迭代器模式的关键是提供一个迭代器去遍历集合,不管集合底层如何实现,只要遍历方式一样就达到目的了。
接下来的学习,需要掌握一些有关Python迭代器的知识,否则下面的代码将很难理解。
先定义一个类:
class Test():
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name} 今年 {self.age}'
def print(self):
pass
现在,要求提供一种能够遍历对象所有属性的迭代器,很简单。
class ObjAttrIterator():
def __init__(self, obj):
self.obj = obj
self.attrs = list(obj.__dict__.keys()) # 所有属性名称
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index >= len(self.attrs):
raise StopIteration
attr = self.attrs[self.index]
return attr, getattr(self.obj, attr)
定义一个 ObjAttrIterator
类,初始化时传入一个实例对象,通过 __init__
属性获得实例对象的所有属性,
一个对象如果实现了 __iter__
方法就是可迭代对象,如果又同时实现了 __next__
方法,那么它就是迭代器,
迭代器的 __iter__
方法通常返回其自身, __next__
提供迭代功能。
下面的代码演示如何使用他们。
t = Test("小明", 14)
iterator = ObjAttrIterator(t)
for attr, value in iterator:
print(attr, value)
name 小明 age 14
程序输出结果。
name 小明
age 14
目前,ObjAttrIterator
迭代器需要单独使用,还不是最方便的方式,
在 Test
类的 __iter__
方法返回 ObjAttrIterator
实例,可以让程序更加简洁。
class ObjAttrIterator():
def __init__(self, obj):
self.obj = obj
self.attrs = list(obj.__dict__.keys()) # 所有属性名称
self.index = -1
def __iter__(self):
return self
def __next__(self):
self.index += 1
if self.index >= len(self.attrs):
raise StopIteration
attr = self.attrs[self.index]
return attr, getattr(self.obj, attr)
class Test():
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name} 今年 {self.age}'
def __iter__(self):
return ObjAttrIterator(self)
def print(self):
pass
t = Test("小明", 14)
for attr, value in t:
print(attr, value)
name 小明 age 14
Test
实现了 __iter__
方法, 它是一个可迭代对象,__iter__
方法返回的是一个迭代器,
在 for
循环内部,一直在用 next
方法遍历这个迭代器,就获取到了对象的所有属性和对应的值。