在 Python 中,当 __iter__ 被调用时 "reset" 一个迭代器是不是一个坏习惯?
In Python, is it a bad practice to "reset" an iterator when __iter__ is called?
例如,假设我有一个 class 用于迭代文件中的记录:
class MySpecialFile:
...
def reset(self):
self._handle.seek(0)
def __iter__(self):
self.reset()
return self
编辑:
我几个月后才看到这个问题,我问了它,觉得有点愚蠢:)。
正如下面的答案所写,具有副作用的 __iter__
方法是一件坏事。如果你想多次迭代你的对象,那么,每次调用 __iter__
:
时你只需要 return 一个新的迭代器对象
class IterableFile:
def __iter__(self):
return FileIterator(self)
回想起来,这很明显,我想这就是我现在感到愚蠢的原因。不确定我在想什么,但我认为我不愿意有两个单独的 classes 的原因是每个新的迭代器都需要创建一个新的文件处理程序(我的 SpecialFile class 只是一个接口在 text/binary 文件之上)当时我觉得 "excessive" 很奇怪。
任何破坏语言结构预期流程的行为都是危险信号,比 "code smell" 更糟糕。这不是 Python 特有的;它适用于任何语言或系统。
但是,请记住关于 "the hobgoblin of little minds" 的限制:
- 您的
reset
是否改善了程序流程?
- 生成的代码是否易于阅读和理解?
如果您已经为必须理解和维护它的人(包括您未来的自己)介绍了这些内容,那么 reset
可能是很好的做法。我持怀疑态度,但我在工作中看到过这种情况。
旁注:为什么在第一次构造迭代器时需要 reset
迭代器?
iter
预计不会有副作用。通过违反这个假设,您的代码会破坏各种各样的事情。比如一个事物是否可迭代的标准测试:
try:
iter(thing)
except TypeError:
do_whatever()
将重置您的文件。同样,itertools consume
recipe:
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
将产生不正确的文件位置,而不是在 consume(your_file, n)
之后推进 n
条记录。在循环之前用 next
跳过前几条记录也会失败:
f = MySpecialFile(whatever)
next(f) # Skip a header, or try, anyway.
for record in f:
# We get the header anyway.
uhoh()
例如,假设我有一个 class 用于迭代文件中的记录:
class MySpecialFile:
...
def reset(self):
self._handle.seek(0)
def __iter__(self):
self.reset()
return self
编辑:
我几个月后才看到这个问题,我问了它,觉得有点愚蠢:)。
正如下面的答案所写,具有副作用的 __iter__
方法是一件坏事。如果你想多次迭代你的对象,那么,每次调用 __iter__
:
class IterableFile:
def __iter__(self):
return FileIterator(self)
回想起来,这很明显,我想这就是我现在感到愚蠢的原因。不确定我在想什么,但我认为我不愿意有两个单独的 classes 的原因是每个新的迭代器都需要创建一个新的文件处理程序(我的 SpecialFile class 只是一个接口在 text/binary 文件之上)当时我觉得 "excessive" 很奇怪。
任何破坏语言结构预期流程的行为都是危险信号,比 "code smell" 更糟糕。这不是 Python 特有的;它适用于任何语言或系统。
但是,请记住关于 "the hobgoblin of little minds" 的限制:
- 您的
reset
是否改善了程序流程? - 生成的代码是否易于阅读和理解?
如果您已经为必须理解和维护它的人(包括您未来的自己)介绍了这些内容,那么 reset
可能是很好的做法。我持怀疑态度,但我在工作中看到过这种情况。
旁注:为什么在第一次构造迭代器时需要 reset
迭代器?
iter
预计不会有副作用。通过违反这个假设,您的代码会破坏各种各样的事情。比如一个事物是否可迭代的标准测试:
try:
iter(thing)
except TypeError:
do_whatever()
将重置您的文件。同样,itertools consume
recipe:
def consume(iterator, n=None):
"Advance the iterator n-steps ahead. If n is None, consume entirely."
# Use functions that consume iterators at C speed.
if n is None:
# feed the entire iterator into a zero-length deque
collections.deque(iterator, maxlen=0)
else:
# advance to the empty slice starting at position n
next(islice(iterator, n, n), None)
将产生不正确的文件位置,而不是在 consume(your_file, n)
之后推进 n
条记录。在循环之前用 next
跳过前几条记录也会失败:
f = MySpecialFile(whatever)
next(f) # Skip a header, or try, anyway.
for record in f:
# We get the header anyway.
uhoh()