How should they be used instead? Maybe I don't understand what you mean by "idiomatic control flow uses exceptions" - could you give an example. Maybe there is some use of exceptions that I'm not quite familiar with in Python.
How should they be used instead? Maybe I don't understand what you mean by "idiomatic control flow uses exceptions" - could you give an example. Maybe there is some use of exceptions that I'm not quite familiar with in Python.
If you call `next()` in Python, this special case is translated to a `StopIteration` exception. But if you use a for-loop, it can directly stop iterating without ever materializing the `StopIteration` exception. So the overhead of Python raise/try-except is already irrelevant for the for-loop.
In particular, this is not idiomatic python:
if "key" in dict_:
value += dict_["key"]
But this is: try:
value += dict_["key"]
except KeyError:
pass
I too hate using the exception handling in this way, and if you aren't careful, you end up papering over other unexpected exceptions in your code, so you have to be (A) very specific in the exception you catch, and (B) keep it in as small a portion of code as possible.I just think it makes for clumsy code - which of the two look better:
try:
value = dict_["key"]
except KeyError:
pass
else:
do_something(value)
OR if "key" in dict_:
do_something(dict["key"])
But it might just be me.According to this article, I think his case is rather weak. The conclusion does not seem to follow from the premise to me.
do_something(dict_.get("key", None))
I use that a lot for data parsing. Passing the exception is not very clean IMHO. I stick to d[key] nomenclature when I need assurance that all the keys are present in the dictionary, and .get(key,None) when I don't.And if you care about the default value being a particular type, when there may also be None in the input stream, do something like:
x.get("key") or []
or
str(x.get("key") or "") # Guarantee strings and avoid "None"!
(a) has one dict operation plus an exception which rarely occurs and is nearly zero cost if it doesn't.
versus
(b) has nearly always two dict operations, plus a possibly incorrect assumption that the dict will not be mutated between the "if key in dict" and "dict[key]" operations.
value += dict_.get('key',0)
Though I agree with using an if in the second example, if there isn't a better way to do the iteration to avoid looking up keys that don't exist.The exception handling approach may also be faster if your code cares (may, because I don't know if the cost of calculating the hash of "key" twice is cheaper than the exception handling overhead).
https://docs.python.org/3/library/exceptions.html#StopIterat...
From https://docs.djangoproject.com/en/3.2/ref/models/querysets/#...
from django.core.exceptions import ObjectDoesNotExist
try:
blog = Blog.objects.get(id=1)
entry = Entry.objects.get(blog=blog, entry_number=1)
except ObjectDoesNotExist:
print("Either the blog or entry doesn't exist.") entry = Entry.objects.filter(blog__id=1,
entry_number=1).first()
if entry is None:
# deal with does not exist
Maybe it's my scala/Java background shining through, but we are big Django users and we ban the "catch exceptions as standard" workflow, because there is almost always a cleaner way...Maybe for some cases, but it does not do the exact same thing, see the comment here: https://stackoverflow.com/a/29455777/1598080
And if we are talking about idiomatic, I think it is maybe a stretch to count this as idiomatic for Python, but given it is documented for Django I think it is fair to call it idiomatic for Django.
Generally speaking, I tend toward the cleanest code being:
blog = Blog.objects.get(id=1)
entry = blog.entry_set.filter(entry_number=1).first()
if entry is None:
handle_missing_entry()
handle_entry(entry)
But it does suffer from having the extra DB query in there, which may or may not be helpful, depending on the surrounding code (and whether or not you'll be using the blog instance anywhere else).Honestly, I normally just use get and let the exception fly. If it's a celery task I'll see the stack trace in flower, or right in the output if it's dev with debug on. Then I would go out of my way to make sure there was never a circumstance where a user requests something that doesn't exist.
The advantage to this over checking the type is that you are still use duck typing. If you check the type then you can only support a specific set of classes.