以下方法在我的课程中,并在完成其工作之前尝试自我填充。引物在它作为其后的处理循环的工作时很懒惰。在这两个循环中重复了五行,对我来说,消除重复的最佳方法是什么并不明显。
@classmethod
def __get_start_words(cls, iterable, n, start_words):
iterator, buffer, sentinel = iter(iterable), Deque(maxlen=n), object()
for _ in range(n):
item = next(iterator, sentinel)
if item is sentinel:
# raise ValueError('iterable was too short to satisfy n')
break
buffer.append(item)
yield item
start_words[buffer.prefix] += 1
while True:
if buffer[0][-1] in cls.TERMINATORS:
start_words[buffer.suffix] += 1
item = next(iterator, sentinel)
if item is sentinel:
break
buffer.append(item)
yield item
是否有一种有效而清晰的方法可以在课程或方法中只编写一次最后五行?
附录
在回答有关prefix
和suffix
的问题时,这里是Deque
类:
class Deque(collections.deque):
"""Deque([iterable[, maxlen]]) -> Deque instance"""
@property
def prefix(self):
"""Property allowing capture of all but last item in deque."""
item = self.pop()
value = tuple(self)
self.append(item)
return value
@property
def suffix(self):
"""Property allowing capture of all but first item in deque."""
item = self.popleft()
value = tuple(self)
self.appendleft(item)
return value
第二版
考虑到其他人不得不说的话,为了提高效率,我写了以下方法:
@classmethod
def __get_start_words(cls, iterable, n, start_words):
iterator, buffer, count = iter(iterable), Deque(maxlen=n), 0
for item, count in zip(iterator, range(n)):
buffer.append(item)
yield item
if count + 1 < n:
raise ValueError('iterable was too short to satisfy n')
start_words[buffer.prefix] += 1
try:
while True:
if buffer[0][-1] in cls.TERMINATORS:
start_words[buffer.suffix] += 1
item = next(iterator)
buffer.append(item)
yield item
except StopIteration:
pass
第三版
该方法的第三个版本改编自Daniel的深刻见解:
@classmethod
def __get_start_words(cls, iterable, n, start_words):
count, buffer = 0, Deque(maxlen=n)
for count, item in enumerate(iterable, 1):
yield item
buffer.append(item)
if count == n:
start_words[buffer.prefix] += 1
if count >= n and buffer[0][-1] in cls.TERMINATORS:
start_words[buffer.suffix] += 1
if count < n:
raise ValueError('iterable was too short to satisfy n')
最终版
这种方法明显优于我的第一个版本 - 感谢那些帮助我的人。
@classmethod
def __get_start_words(cls, iterable, n, start_words):
buffer = Deque(maxlen=n)
for count, item in enumerate(iterable, 1):
yield item
buffer.append(item)
if count == n:
start_words[buffer.prefix] += 1
if count >= n and buffer[0][-1] in cls.TERMINATORS:
start_words[buffer.suffix] += 1
if len(buffer) < n:
raise ValueError('iterable was too short to satisfy n')
答案 0 :(得分:4)
使用for
- 循环:
@classmethod
def __get_start_words(cls, iterable, n, start_words):
buffer = Deque(maxlen=n)
for idx, item in enumerate(iterable, 1):
buffer.append(item)
yield item
if idx == n:
start_words[buffer.prefix] += 1
if idx >= n and buffer[0][-1] in cls.TERMINATORS:
start_words[buffer.suffix] += 1
if len(buffer) < n:
raise ValueError('iterable was too short to satisfy n')
关于您的第二个版本的一些想法:使用count
时不需要islice
:
for item in islice(iterator, n):
buffer.append(item)
yield item
if len(buffer) < n:
raise ValueError('iterable was too short to satisfy n')
进一步重构导致:
@classmethod
def __get_start_words(cls, iterable, n, start_words):
iterable = iter(iterable)
buffer = deque(islice(iterable, n-1))
yield from buffer
if len(buffer) < n - 1:
raise ValueError('iterable was too short to satisfy n')
start_words[tuple(buffer)] += 1
for item in iterable:
buffer.append(item)
yield item
first = buffer.popleft()
if first[-1] in cls.TERMINATORS:
start_words[tuple(buffer)] += 1