Reputation: 193
I got sick and tired of writing Python (2.7) code like this:
if "george" in cats and cats["george"] is not None:
special_cat = cats["george"]
# do something with special_cat
So I wrote a generator that returns either zero or one object:
def maybe_get(d, k):
if k in d and d[k] is not None:
yield d[k]
else:
return
Now I can make more original code snippet more compact, like so:
for special_cat in maybe_get(cats, "george"):
# do something with special_cat
Using a for-loop for this purpose looks odd, though. I’d much rather use a context manager:
with maybe_get(cats, "george") as special_cat:
# do something with special_cat
But I can’t figure out any way to make a context manager skip over the block of code it manages. (The @contextmanager
decorator, for example, will raise a RuntimeError
if the generator does not yield at least one value.) Is there a trick that I’m missing?
Upvotes: 2
Views: 618
Reputation: 1121654
You cannot use a context manager to 'skip' code blocks, that is what conditional are for. All a context manager can do is hook in to the block enter and exit signals, not control if the block is entered in the first place.
I'd use:
special_cat = cats.get("george")
if special_cat is not None:
# do something with special_cat
This has the advantage of being readable and simple. Any shenanigans with generators or context managers would increase the surprise for new maintainers of your code. And remember: you are a new maintainer after a year or two away from a codebase too.
Upvotes: 3