So I'm working on making a simple research bot but I've run into a problem. I was following a guide on using wolfram alpha in python and when I test it I sometimes get the error
Traceback (most recent call last):
File "python", line 6, in <module>
StopIteration`.
Here is my code:
import wolframalpha
import wikipedia
client = wolframalpha.Client('my_id')
q=input('Problem: ')
res = client.query(q)
print(next(res.results).text)
It only happens with some queries and it often works, but still its rather annoying. I looked online but didn't find any help, so I don't know if this is new or something is wrong with my code. Anyway, here is a link to a repl I made where its not working here. Try it with "uranium" I know that one brings the error and so do a few others I've tried. Thanks!
This error is telling you that your query had no results.
This line:
print(next(res.results).text)
… calls next
on an iterator, res.results
, without a default value:
Retrieve the next item from the iterator by calling its
__next__()
method. If default is given, it is returned if the iterator is exhausted, otherwiseStopIteration
is raised.
If res
had no results to show you, res.results
is an empty iterator. Meaning it's exhausted right from the start, so when you call next
on it, you're going to get StopIteration
.
And just passing a default isn't going to do much good here. Consider this:
print(next(res.results, None).text)
Now, if there are no results, next
will return your default value None
, and you'll immediately try to do None.text
, which will just raise an AttributeError
.
One way to fix this is to just handle the error:
try:
print(next(res.results).text)
except StopIteration:
print('No results')
Another is to break that compound expression up into simpler ones, so you can use a default:
result = next(res.results, None)
print(res.text if res else 'No results')
However, res
can include 2 or 3 results just as easily as 0—that's the whole reason it returns an iterator. And usually, you're going to want all of them, or at least a few of them. If that's the case, the best solution is to use a for
loop. Iterators are born hoping they'll be used in a for
loop, because it makes everyone's like easier:
for result in res.results:
print(result.text)
This will do nothing if results
is empty, print one result if there's only one, or print all of the results if there are multiple.
If you're worried about getting 500 results when you only wanted a few, you can stop at, say, 3:
for result in itertools.islice(res.results, 3):
print(result.text)
… or:
for i, result in enumerate(res.results):
print(result.text)
if i > 2: break