What are the differences between the `None` handling of Typing in Python and `Err != nil` in Golang?
Posted by Wide-Milk1195@reddit | Python | View on Reddit | 19 comments
I'm a junior programmer with limited understanding of Python and Golang. However, through coding, I've noticed a commonality: Python functions return "value | None", while Golang functions return "value &err". When dealing
with Python function return values, I need to write:
```
data = func()
if data is None:
# raise Error
# Log
# ...
# I haven't used assert in a production environment, only in tests
```
When dealing with Golang function return values, I need to write:
```
data,err = func()
if err != nil:
# return error
# Log
# ...
```
Writing rigorous Python code is no less cumbersome than Golang. I'd like to ask intermediate to advanced Python developers: can Python with strict typing (handling None and Any) handle medium-sized projects?
Python-ModTeam@reddit
Hi there, from the /r/Python mods.
We have removed this post as it is not suited to the /r/Python subreddit proper, however it should be very appropriate for our sister subreddit /r/LearnPython or for the r/Python discord: https://discord.gg/python.
The reason for the removal is that /r/Python is dedicated to discussion of Python news, projects, uses and debates. It is not designed to act as Q&A or FAQ board. The regular community is not a fan of "how do I..." questions, so you will not get the best responses over here.
On /r/LearnPython the community and the r/Python discord are actively expecting questions and are looking to help. You can expect far more understanding, encouraging and insightful responses over there. No matter what level of question you have, if you are looking for help with Python, you should get good answers. Make sure to check out the rules for both places.
Warm regards, and best of luck with your Pythoneering!
latkde@reddit
In Python, it is unusual for functions to return
Noneupon error. They generally ought to raise exceptions. To write rigorous code, often the best approach is to do nothing, and to let the exception bubble up. Catching exceptions only really makes sense in two situations:Some Python code – especially a lot AI-generated code – uses exception handling in this style:
This is generally worse than useless. (Again: unless this is a deliberate error boundary.) This leads to exactly the kind of Go-style error handling that you rightfully bemoan. But that is not good Python style.
Some functions should indeed return
Noneinstead of raising an exception – when the absence of a result is completely normal, not an error. In such situations, typical Golang code would also just returnnil, not a non-nil error. There is a bit of a grey area where either solution might be appropriate. For example, the standard librarystr.index()function raisesValueErrorwhen the substring cannot be found:Personally, I would have preferred it if that function would return an
int | Noneinstead. However, the current design is a perfectly Pythonic solution. Note that Golang uses the C convention of returning -1 when the substring cannot be found, which is potentially unsafe.Outside_Complaint755@reddit
Side note, in Python if you want to search for a substring and always get back an int without raising a ValueError, use
str.find(substring), which returns -1 if the substring is.not found. Because it doesn't raise an exception, it is slightly faster if the match fails. The advantage of theindexmethod is that it exists for multiple sequence types, including strings, lists, and tuples, allowing it to be used in more generalized code.Wide-Milk1195@reddit (OP)
Okay, I understand a little bit now, thank you.
GhostVlvin@reddit
In golang it actually returns error code alongside result.
While in python it is more like in C, if result is enormous then it was an error code. Otherwise it is an actual result
nekokattt@reddit
The way C and Python deal with error handling is totally different
Smallpaul@reddit
Enormous?
janek3d@reddit
You should return None only if it's valid value your function can use. If you want it to indicate that there is some error, then the function should raise the Exception
Wide-Milk1195@reddit (OP)
I discovered that if any branch of a function's return value does not meet the type requirement, it is inferred to be "value | None", even if an error is thrown.
shadowdance55@reddit
Python implicitly returns None unless otherwise defined. I.e. if at any point your function stops and there is no return statement, it will return None. So if some of your branches return a certain type, and others have no return, it will be inferred as you described.
Also, exceptions are completely unrelated to the return value. When an exception is raised the function stops, breaking the overall program flow unless it's handled somewhere.
cheerycheshire@reddit
What is your typechecker?
+Do you have minimal example of it happening? It may be that there is a branch of the code that theoretically might be reached and doesn't have a return nor raises an error - and python does implicitly return None in such cases. Often such type inferring is about how you write ifs - technically some branch can't be entered anymore when you know that earlier info, but typecher still sees that branch and only sees nearby context, not all previous if checks.
Wide-Milk1195@reddit (OP)
The PyLance plugin in VS Code is based on PyRight; I've enabled the standard level.
SwampFalc@reddit
Sure, but in this particular case, it seems the intention is to raise an Exception afterwards. If that matches the use case, then this is fine.
By which I mean, whether or not something is an error, depends fully on the context. Any given function could return None without it being an error in and of itself, but that can then become an error once the result gets interpreted.
cheerycheshire@reddit
I agree, but the only thing I'd change: raise an exception. Because "the Exception" sounds like it should raise Exception type specifically. It should be a child class, even very basic, to only catch a specific exception instead of all things Exception.
Sorry for being nitpicky, but in the past i had inherited code that used Exception for control flow (where it could've been managed otherwise...) and saw promising small libs(!) that used just Exception instead of a specific one...
cointoss3@reddit
You throw an exception only if your program can’t move forward. You return None if that’s useful, but usually you just raise and let the error bubble up. You don’t do exception handling at each function, you just let the error bubble up to a more central place where they are handled if your program can continue.
One of the big beginner mistakes in Python is trying to handle exceptions in too many places.
turbothy@reddit
What is medium size to you?
Wide-Milk1195@reddit (OP)
Sorry, I'm a junior programmer. I currently believe that medium-sized programs require at least two people to develop together. I haven't been working for long, so please forgive any unclear descriptions.
thomasfr@reddit
IMO writing robust, fault tolerant code in any language that uses exceptions as a regular error handling mechanism is more cumbersome.
theGiogi@reddit
They’re called type HINTS for a reason. It’s an addition to the language and it does make it easier to spot issues before tests. But a lot of the Python package ecosystem does not to strict type hinting so YMMV.
I use the stateless package to condense all business logic in pure generators that are extensively typed. Using this algebraic effects approach you separate out all side effects (where external packages are used) and you can naturally handle their specifics away from your business logic.