4.6 带有外部状�的生�器函数¶
问题¶
ä½ æƒ³å®šä¹‰ä¸€ä¸ªç”Ÿæˆ�器函数,但是它会调用æŸ�ä¸ªä½ æƒ³æš´éœ²ç»™ç”¨æˆ·ä½¿ç”¨çš„å¤–éƒ¨çŠ¶æ€�值。
解决方案¶
å¦‚æžœä½ æƒ³è®©ä½ çš„ç”Ÿæˆ�器暴露外部状æ€�给用户,
åˆ«å¿˜äº†ä½ å�¯ä»¥ç®€å�•的将它实现为一个类,然å�ŽæŠŠç”Ÿæˆ�器函数放到 __iter__() 方法ä¸è¿‡åŽ»ã€‚æ¯”å¦‚ï¼š
from collections import deque
class linehistory:
def __init__(self, lines, histlen=3):
self.lines = lines
self.history = deque(maxlen=histlen)
def __iter__(self):
for lineno, line in enumerate(self.lines, 1):
self.history.append((lineno, line))
yield line
def clear(self):
self.history.clear()
ä¸ºäº†ä½¿ç”¨è¿™ä¸ªç±»ï¼Œä½ å�¯ä»¥å°†å®ƒå½“å�šæ˜¯ä¸€ä¸ªæ™®é€šçš„ç”Ÿæˆ�器函数。
然而,由于å�¯ä»¥åˆ›å»ºä¸€ä¸ªå®žä¾‹å¯¹è±¡ï¼ŒäºŽæ˜¯ä½ å�¯ä»¥è®¿é—®å†…部属性值,
比如 history 属性或者是 clear() 方法。代ç �示例如下:
with open('somefile.txt') as f:
lines = linehistory(f)
for line in lines:
if 'python' in line:
for lineno, hline in lines.history:
print('{}:{}'.format(lineno, hline), end='')
讨论¶
关于生æˆ�å™¨ï¼Œå¾ˆå®¹æ˜“æŽ‰è¿›å‡½æ•°æ— æ‰€ä¸�能的陷阱。
如果生æˆ�器函数需è¦�è·Ÿä½ çš„ç¨‹åº�其他部分打交é�“çš„è¯�(比如暴露属性值,å…�许通过方法调用æ�¥æŽ§åˆ¶ç‰ç‰),
å�¯èƒ½ä¼šå¯¼è‡´ä½ 的代ç �异常的å¤�æ�‚。
如果是这�情况的�,�以考虑使用上�介�的定义类的方�。
在 __iter__() 方法ä¸å®šä¹‰ä½ 的生æˆ�器ä¸�会改å�˜ä½ 任何的算法逻辑。
由于它是类的一部分,所以å…�è®¸ä½ å®šä¹‰å�„ç§�属性和方法æ�¥ä¾›ç”¨æˆ·ä½¿ç”¨ã€‚
一个需è¦�注æ„�çš„å°�åœ°æ–¹æ˜¯ï¼Œå¦‚æžœä½ åœ¨è¿ä»£æ“�作时ä¸�使用for循环è¯å�¥ï¼Œé‚£ä¹ˆä½ 得先调用 iter() 函数。比如:
>>> f = open('somefile.txt')
>>> lines = linehistory(f)
>>> next(lines)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'linehistory' object is not an iterator
>>> # Call iter() first, then start iterating
>>> it = iter(lines)
>>> next(it)
'hello world\n'
>>> next(it)
'this is a test\n'
>>>