When developing the Python API, are there more Pythonic throwing exceptions or returning false / None, etc.?

I am using a Python based API where there are many functions for queries like doesPointExist , findPoint , canCreateNewPoint , etc. where a negative result throws an exception. This makes the code much more cluttered with try / catch statements rather than directly using the result as a boolean.

Since I'm not a Python expert, I wonder if this project is Pythonic or not? I have not seen such a design in standard libraries, so I suppose such use of exceptions in Python APIs is not approved?

+6
source share
5 answers

API design is a bit of an art. The function name should indicate how it will behave, including setting user expectations. A function called findPoint implies that the search may fail, so the case when such a point does not exist is not exceptional and may return None to signal the result. However, a function named getPoint would mean that it can always return the requested point. The failure will be unexpected and cause an exception.

+6
source

Sounds like a poorly designed API.

  • The doesPointExist function must return True or False , it must not throw an exception if the point does not exist.
  • The findPoint function must return a Point or None object when the object cannot be found.
  • The canCreateNewPoint function must return True or False for the same reasons.

Exceptions for exceptional cases.

+6
source

I do not agree that you will not find this in the standard library. For example, "abc".index("d") raises a ValueError , many libraries throw exceptions.

I would say that it depends on what the consequences of a failed action are.

  • If the caller can work with the return value unchanged, I would return an empty value (or False if this is a yes or no question).
  • If the call failed, I would throw an exception. For example, findPoint() can do this if it usually returns the Point object that the caller wants to work with.
+3
source

1, I would recommend using an exception for very specific cases, so you do not need to test them in normal situations.

2, you should read the instructions of the PEP8 Naming Convention regarding the names of your functions.

+2
source

This is not unique to Python. Other answers are good, but only some additional thoughts that did not fit into the comment:

  • You use exceptions if you do not want (or need) to check the result. In this mode, you just do it, and if there is an error somewhere, you make an exception. Getting rid of explicit checks makes shorter code, and you still get good debugging information when you get an exception, so it's common. This is the EAFP style described above (easier to ask than permission).
  • You use return codes when you want to check the result. Explicit verification is sometimes necessary if failures do not always fail or help debug complex code streams. This is sometimes called the LBYL style (look before you jump).

In Python, like most interpreted languages, since the overhead is so high, exceptions are relatively cheap, so it's much wider to use EAFP in Python than, say, C ++, where overhead is lower and exceptions are (relatively) more expensive.

Note that a function may give a return value and may possibly throw an exception.

In your example, a function like doesPointExist implies that the user really wants to check access before trying something. This is LBYL. Throwing an exception as the result value is part of the EAFP programming style and does not make sense for this function - if you want this style, you will not check it, you just do it and catch the exception when the point does not exist.

However, even here there are assumptions - that you gave a valid point. It would be nice if the function returns True / False for whether a point exists, throwing an exception if something that was not a point was passed to it.

+2
source

Source: https://habr.com/ru/post/958482/


All Articles