DEV Community

Discussion on: Python exceptions considered an anti-pattern

Collapse
 
rpalo profile image
Ryan Palo

That's interesting. So far, from what I've seen, raising Exceptions seems like a valid, Pythonic way to handle edge cases.

I'm interested to find out your opinion on how I'd do things normally.

For the division function, it seems like a totally valid way to go to let it raise its own ZeroDivisionError. Looking in log files or seeing that come up in the terminal would be as good a message as any to communicate what's happening. You would see that a function called divide is raising a ZeroDivisionError, and you would know exactly what the problem is and that you need to track down where a zero is getting sent to your divide function.

And leaving it up to client code to handle the propagated ZeroDivisionError is a pretty standard idiom in Python. If you really feel the need to catch the error, you could maybe raise your own signaling the bad input value?

def divide(first: float, second: float) -> float:
    if second == 0:
        raise ValueError("Zero is an invalid divisor.")

    return first / second
Enter fullscreen mode Exit fullscreen mode

In fact, Python's documentation itself recommends this idiom in the bisect module docs. If a binary search doesn't find the value it's looking for, it doesn't return None, it raises a ValueError. It's up to the client to handle that exception.


All of that to say, I think the wrapped value idea is neat, and a useful idiom from languages like Go and Rust. I can see that it would definitely have some use cases in Python where it would be the best. I agree that you wouldn't want to lean on Exceptions for standard control flow for the most part.

But using exceptions to indicate a state other than the happy path seems like it's definitely not an anti-pattern in Python, and in a lot of cases, it's the Pythonic way to go.

Does that make sense at all?

Collapse
 
sobolevn profile image
Nikita Sobolev

I like to separate two kind of layers I have in my app: logic and application.

Logic is almost independent, it is my choice how to work with it. It allows a huge portion of freedom.
On the other hand it requires to be readable. Because there are no other-projects-like-this-one. So, that's why it is important for me to make exceptions crystal clear. Other people does not know if my FetchUser class is going to raise or not. And I do want to make this contract explicit.

On the lower, application, level I am using the existing stuff. Like django, celery, scrapy. And I need to respect their APIs. And, for example, django uses a lot of exceptions to control the execution flow. So, I prefer to raise on this level. And check that every exception is meaningful with tests.

That's how I see the big picture. Hope that you will find a proper use-cases for returns!