可爱的 Python: Python 之优雅与瑕疵,第 1 部分
2008-09-30 12:57:47 来源:WEB开发网清单 10. 索引操作成功和失败的示例
>>> r[4]
4
>>> i[4]
TypeError: unindexable object
对于每种序列/迭代器类型,只要费一番功夫,总能够获得其中的特定条目。一种方法是进行循环,直至到达所需的对象。另一种古怪的解决方案如下:
清单 11. 获得索引的怪方法
>>> thing, temp = itertools.tee(thing)
>>> zip(temp, '.'*5)[-1][0]
4
对 itertools.tee() 的预调用保留了原始迭代器。对于切片,可以按照特殊方式使用 itertools.islice() 函数。
清单 12. 获得一个切片的特殊方法
>>> r[4:9:2]
[4, 6, 8]
>>> list(itertools.islice(r,4,9,2)) # works for iterators
[4, 6, 8]
类包装器
为了方便起见,可以将这些技术组合成一个类包装器:
清单 13. 使迭代器可编制索引
>>> class Indexable(object):
... def __init__(self, it):
... self.it = it
... def __getitem__(self, x):
... self.it, temp = itertools.tee(self.it)
... if type(x) is slice:
... return list(itertools.islice(self.it, x.start, x.stop, x.step))
... else:
... return zip(temp, range(x+1))[-1][0]
... def __iter__(self):
... self.it, temp = itertools.tee(self.it)
... return temp
...
>>> integers = Indexable(itertools.count())
>>> integers[4]
4
>>> integers[4:9:2]
[4, 6, 8]
所以,通过某些措施,可以让一个对象同时表现得像序列和迭代器。但是,费这么大力气实际上 应该是不必要的;无论涉及的是序列还是迭代器,编制索引和切片都应该是 “可行的”。
注意,Indexable 类包装器仍然不够灵活。主要问题是,每次都要创建迭代器的一个新副本。更好的方法应该是在对序列切片时缓存序列的头部,然后在以后访问已经检查的元素时使用所缓存的头部。当然,在使用迭代器时,要在占用的内存和速度之间有所取舍。但是,如果 Python 本身能够 “在幕后” 完成这些,就再好不过了 —— “高级用户” 可以对行为进行调优,而一般程序员应该不需要考虑这些。
在本系列的下一期中,我将讨论如何使用属性语法访问方法。
更多精彩
赞助商链接