Dan*_*Dan 127 python generator
有没有一种简单的方法来测试生成器是否没有项目,比如peek,hasNext,isEmpty,这些是什么?
Joh*_*uhy 88
建议:
def peek(iterable):
try:
first = next(iterable)
except StopIteration:
return None
return first, itertools.chain([first], iterable)
Run Code Online (Sandbox Code Playgroud)
用法:
res = peek(mysequence)
if res is None:
# sequence is empty. Do stuff.
else:
first, mysequence = res
# Do something with first, maybe?
# Then iterate over the sequence:
for element in mysequence:
# etc.
Run Code Online (Sandbox Code Playgroud)
Dav*_*ger 49
你问题的简单答案:不,没有简单的方法.有很多解决方法.
真的不应该有一个简单的方法,因为生成器是什么:一种输出一系列值而不将序列保存在内存中的方法.所以没有向后遍历.
你可以编写一个has_next函数,或者甚至可以将它作为一个带有花式装饰器的方法打到生成器上,如果你愿意的话.
raz*_*zz0 26
一种简单的方法是使用next()的可选参数,如果生成器耗尽(或为空),则使用该参数.例如:
iterable = some_generator()
_exhausted = object()
if next(iterable, _exhausted) == _exhausted:
print('generator is empty')
Run Code Online (Sandbox Code Playgroud)
编辑:更正了mehtunguh评论中指出的问题.
jua*_*cks 10
next(generator, None) is not None
或者更换,None但无论你知道什么价值都不在您的发电机中.
编辑:是的,这将跳过生成器中的1项.但是,我经常检查生成器是否为空以用于验证目的,然后不要真正使用它.或者我做的事情如下:
def foo(self):
if next(self.my_generator(), None) is None:
raise Exception("Not initiated")
for x in self.my_generator():
...
Run Code Online (Sandbox Code Playgroud)
也就是说,如果您的生成器来自某个函数,则可以使用此函数generator().
最好的方法,恕我直言,将避免一个特殊的测试.大多数情况下,使用发电机是测试:
thing_generated = False
# Nothing is lost here. if nothing is generated,
# the for block is not executed. Often, that's the only check
# you need to do. This can be done in the course of doing
# the work you wanted to do anyway on the generated output.
for thing in my_generator():
thing_generated = True
do_work(thing)
Run Code Online (Sandbox Code Playgroud)
如果这还不够好,您仍然可以执行明确的测试.此时,thing将包含生成的最后一个值.如果没有生成任何内容,它将是未定义的 - 除非您已经定义了变量.你可以查看它的值thing,但这有点不可靠.相反,只需在块中设置一个标志,然后检查它:
if not thing_generated:
print "Avast, ye scurvy dog!"
Run Code Online (Sandbox Code Playgroud)
我讨厌提供第二个解决方案,特别是我不会自己使用的解决方案,但是,如果你绝对不得不这样做而不使用生成器,就像在其他答案中一样:
def do_something_with_item(item):
print item
empty_marker = object()
try:
first_item = my_generator.next()
except StopIteration:
print 'The generator was empty'
first_item = empty_marker
if first_item is not empty_marker:
do_something_with_item(first_item)
for item in my_generator:
do_something_with_item(item)
Run Code Online (Sandbox Code Playgroud)
现在我真的不喜欢这个解决方案,因为我认为这不是生成器的使用方式.
在 Mark Ransom 的提示下,这里有一个类,您可以使用它来包装任何迭代器,以便您可以提前查看、将值推回流并检查是否为空。这是一个简单的想法和一个简单的实现,我在过去发现它非常方便。
class Pushable:
def __init__(self, iter):
self.source = iter
self.stored = []
def __iter__(self):
return self
def __bool__(self):
if self.stored:
return True
try:
self.stored.append(next(self.source))
except StopIteration:
return False
return True
def push(self, value):
self.stored.append(value)
def peek(self):
if self.stored:
return self.stored[-1]
value = next(self.source)
self.stored.append(value)
return value
def __next__(self):
if self.stored:
return self.stored.pop()
return next(self.source)
Run Code Online (Sandbox Code Playgroud)
小智 6
刚刚落入这个线程并意识到缺少一个非常简单易读的答案:
def is_empty(generator):
for item in generator:
return False
return True
Run Code Online (Sandbox Code Playgroud)
如果我们不打算消耗任何项目,那么我们需要将第一个项目重新注入生成器:
def is_empty_no_side_effects(generator):
try:
item = next(generator)
def my_generator():
yield item
yield from generator
return my_generator(), False
except StopIteration:
return (_ for _ in []), True
Run Code Online (Sandbox Code Playgroud)
例子:
>>> g=(i for i in [])
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
True
>>> g=(i for i in range(10))
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
False
>>> list(g)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Run Code Online (Sandbox Code Playgroud)
对于显而易见的方法感到抱歉,但最好的方法是:
for item in my_generator:
print item
Run Code Online (Sandbox Code Playgroud)
现在您在使用时检测到生成器是空的。当然,如果生成器为空,则永远不会显示项目。
这可能不完全适合您的代码,但这就是生成器的习惯用法:迭代,所以也许您可能会稍微改变您的方法,或者根本不使用生成器。
要查看生成器是否为空,您所需要做的就是尝试获得下一个结果。当然,如果您还没有准备好使用该结果,那么您必须存储它以便稍后再次返回。
这是一个包装类,可以将其添加到现有迭代器中以添加__nonzero__测试,因此您可以使用简单的if. 它可能也可以变成装饰器。
class GenWrapper:
def __init__(self, iter):
self.source = iter
self.stored = False
def __iter__(self):
return self
def __nonzero__(self):
if self.stored:
return True
try:
self.value = next(self.source)
self.stored = True
except StopIteration:
return False
return True
def __next__(self): # use "next" (without underscores) for Python 2.x
if self.stored:
self.stored = False
return self.value
return next(self.source)
Run Code Online (Sandbox Code Playgroud)
以下是您如何使用它:
with open(filename, 'r') as f:
f = GenWrapper(f)
if f:
print 'Not empty'
else:
print 'Empty'
Run Code Online (Sandbox Code Playgroud)
请注意,您可以随时检查是否为空,而不仅仅是在迭代开始时。
| 归档时间: |
|
| 查看次数: |
60281 次 |
| 最近记录: |