I have a generator like so:
def iterate_my_objects_if_something(self):
for x in self.my_objects:
if x.something:
yield x
Which I call like so:
for x in self.iterate_my_objects_if_something():
pass
In the case where there is nothing to return, this tries to iterate over NoneType and throws an exception.
How do I return an empty generator instead?
Just do a simple check:
def iterate_my_objects_if_something(self):
if self.my_objects:
for x in self.my_objects:
if x.something:
yield x
It is important to know, which iteration causes the error. That is certainly pointed in traceback, but in this case traceback is not necessary (keep reading).
After you take a look at that, it is obvious, but worth clarifying that:
empty generator is not of NoneType
, so iterating through it will not cause such issue:
>>> def test_generator():
for i in []:
yield i
>>> list(test_generator()) # proof it is empty
[]
>>> for x in test_generator():
pass
>>>
generator is recognized by Python during definition (I am simplifying) and trying to mix generators and simple functions (eg. by using conditional, as below) will be a syntax error:
>>> def test_generator_2(sth):
if sth:
for i in []:
yield i
else:
return []
SyntaxError: 'return' with argument inside generator (<pyshell#73>, line 6)
Based on the above the conclusion is that the error is not about iterating through iterator, but what happens when it is created (the code within generator):
def iterate_my_objects_if_something(self):
for x in self.my_objects: # <-- only iteration inside generator
if x.something:
yield x
So seemingly in some cases self.my_objects
becomes None
.
To fix that issue either:
self.my_objects
is always an iterable (eg. empty list []
), orcheck it before iteration:
def iterate_my_objects_if_something(self):
# checks, if value is None, otherwise assumes iterable:
if self.my_objects is not None:
for x in self.my_objects:
if x.something:
yield x
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With