Reputation: 23
Is there a way to check for arguments in a Python generator and have an Exception raised instead of having the generator object returned?
Consider the following function for example:
def find_files(directory, pattern="*"):
if not os.path.isdir(directory):
raise ValueError("Invalid directory: " + directory)
for root, _, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
yield os.path.join(root, basename)
When creating the generator object,
g = find_files('/non/existent/path')
an exception is not raised even if the path '/non/existent/path' does not exist. However, when using the generator (iterating through g), which could be much later in code, an error is thrown.
I'd prefer to have the error thrown when attempting to create the generator object instead.
Upvotes: 2
Views: 305
Reputation: 310049
the only good way that I know of is to wrap the (non-checking) generator in a function which does the checking:
def _find_files(directory, pattern):
for root, _, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
yield os.path.join(root, basename)
def find_files(directory, pattern="*"):
if not os.path.isdir(directory):
raise ValueError("Invalid directory: " + directory)
return _find_files(directory, pattern)
the reason for this is that a generator (by definition) doesn't execute anything until its next
(__next__
in python3.x) method is called. At that point, it executes all the code up to the first yield
and then stops executing until the next time .next()
is called and so on.
The above solution is pretty general concept that can be used for checking stuff before a generator starts up -- And, barring some pretty intense introspection, it should be able to be used as a drop in replacement for most generators where this sort of thing might be necessary.
Upvotes: 4