可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Currently I'm doing this:
try:
something = iterator.next()
# ...
except StopIteration:
# ...
But I would like an expression that I can place inside a simple if
statement.
Is there anything built-in which would make this code look less clumsy?
any()
returns False
if an iterable is empty, but it will potentially iterate over all the items if it's not.
I only need it to check the first item.
Someone asks what I'm trying to do.
I have written a function which executes an SQL query and yields its results.
Sometimes when I call this function I just want to know if the query returned anything and make a decision based on that.
回答1:
any
won't go beyond the first element if it's True. In case the iterator yields something false-ish you can write any(True for _ in iterator)
.
回答2:
In Python 2.6+, if name sentinel
is bound to a value which the iterator can't possibly yield,
if next(iterator, sentinel) is sentinel:
print('iterator was empty')
If you have no idea of what the iterator might possibly yield, make your own sentinel (e.g. at the top of your module) with
sentinel = object()
Otherwise, you could use, in the sentinel role, any value which you "know" (based on application considerations) that the iterator can't possibly yield.
回答3:
This isn't really cleaner, but it shows a way to package it in a function losslessly:
def has_elements(iter):
from itertools import tee
iter, any_check = tee(iter)
try:
any_check.next()
return True, iter
except StopIteration:
return False, iter
has_el, iter = has_elements(iter)
if has_el:
# not empty
This isn't really pythonic, and for particular cases, there are probably better (but less general) solutions, like the next default.
first = next(iter, None)
if first:
# Do something
This isn't general because None can be a valid element in many iterables.
回答4:
you can use:
if zip([None], iterator):
# ...
else:
# ...
but it's a bit nonexplanatory for the code reader
回答5:
What about:
In [1]: i=iter([])
In [2]: bool(next(i,False))
Out[2]: False
In [3]: i=iter([1])
In [4]: bool(next(i,False))
Out[4]: True
回答6:
__length_hint__
estimates the length of list(it)
- it's private method, though:
x = iter( (1, 2, 3) )
help(x.__length_hint__)
1 Help on built-in function __length_hint__:
2
3 __length_hint__(...)
4 Private method returning an estimate of len(list(it)).
回答7:
This is an overkill iterator wrapper that generally allows to check whether there's a next item (via conversion to boolean). Of course pretty inefficient.
class LookaheadIterator ():
def __init__(self, iterator):
self.__iterator = iterator
try:
self.__next = next (iterator)
self.__have_next = True
except StopIteration:
self.__have_next = False
def __iter__(self):
return self
def next (self):
if self.__have_next:
result = self.__next
try:
self.__next = next (self.__iterator)
self.__have_next = True
except StopIteration:
self.__have_next = False
return result
else:
raise StopIteration
def __nonzero__(self):
return self.__have_next
x = LookaheadIterator (iter ([]))
print bool (x)
print list (x)
x = LookaheadIterator (iter ([1, 2, 3]))
print bool (x)
print list (x)
Output:
False
[]
True
[1, 2, 3]
回答8:
A little late, but... You could turn the iterator into a list and then work with that list:
# Create a list of objects but runs out the iterator.
l = [_ for _ in iterator]
# If the list is not empty then the iterator had elements; else it was empty.
if l :
pass # Use the elements of the list (i.e. from the iterator)
else :
pass # Iterator was empty, thus list is empty.