要判断一个Pythonista编写的代码够不够pythonic,一个很重要的标准就是看他能不能灵活运用迭代器。
首先要介绍一下什么是迭代器:在python中有两种循环语句,while和for。通常我们可以以c风格来使用它们,但是python额外提供了另外一种更为方便和高效的使用方式。通俗的来说就是边生产边消费。代码易读性和简洁高效性之争
首先要介绍一下几个概念之间得差异:
-
可迭代对象: 除了列表、元组、字符串、元组、集合、字典等序列外,只要实现了__iter__和__getitem__中任意一个方法的对象都是可以进行迭代的。不同的是,在进行迭代的时候解释器会调用iter函数,iter函数会检查对象是否实现了__iter__方法,如果实现了就会调用它得到一个生成器,如果没有实现__iter__方法但是实现了 __getitem__方法,Python 会创建一个迭代器, 尝试按顺序(从索引 0 开始) 获取元素。isinstance(objiect, Iterable)只会检测__iter__方法,忽略了__getitem__方法。
# coding=utf8 from collections import Iterable list_a = [3, 3, 45, 6] dict_b = {'a': 'ji', 'b': 'ok', 'c': 'illegall'} set_c = {'df', 'fdk', 'lo'} tuple_d = ('jfk', 'dj', 'ilsl') str_e = 'jkilljls' isinstance(list_a, Iterable) # True 列表是可迭代对象 isinstance(dict_b, Iterable) # True 字典是可迭代对象 isinstance(set_c, Iterable) # True 集合是可迭代对象 isinstance(tuple_d, Iterable) # True 元组是可迭代对象 isinstance(str_e, Iterable) # True 字符串是可迭代对象
class Queue: def __init__(self, q): self.queue = q def __iter__(self): for item in self.queue: yield item # def __getitem__(self, item): # return self.queue[item] queue = Queue([1, 4, 5, 8]) print(isinstance(queue, Iterable)) #True 只要实现了__iter__方法则该对象就是可迭代对象,还有其他情况见后面
class Queue: def __init__(self, q): self.queue = q #def __iter__(self): # for item in self.queue: # yield item def __getitem__(self, item): return self.queue[item] queue = Queue([1, 4, 5, 8]) isinstance(queue, Iterable) #False 没有实现__iter__方法,但是实现了__getitem__方法也是可迭代对象 #Iterable只对__iter__方法进行检测 for item in queue: # 只要实现了__iter__和__getitem__中的任意一个,则该对象都是可以进行迭代的。 print(item)
-
迭代器: 实现了next方法和__iter__方法的对象,且next方法实现了迭代协议,__iter__方法返回迭代器。
如下是一个迭代器类,可以产生迭代器对象,对迭代器对象调用iter函数返回迭代器类自身,迭代环境中自动调用__next__方法。class iter: def __init__(self, data): self.data = data self.now = 0 def __iter__(self): return self def __next__(self): if self.now < data: self.now += 1 return (self.now-1)**2 raise StopIteration
-
生成器:生成器是一种特殊的迭代器,生成器自动实现了“迭代器协议”(即__iter__和next方法),不需要再手动实现两方法。
3.1 生成器表达式:可以使用表达式来得到生成器
使用生成器表达式可以非常轻松的得到生成器,只要将列表解析式中的方括号换成圆括号就可以了。(x for x in range(5)) # iterator
3.2 生成器函数:在函数中使用关键词yield得到生成器
def gen(num): cou = 0 while cou < num: yield cou cou += 1