TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Python errors as values: Comparing useful patterns from Rust and Go

41 点作者 danfarrelly超过 1 年前

20 条评论

js2超过 1 年前
The most important thing about writing code is that you write it idiomatically for the language it is in. With Python, idiomatic code is known as Pythonic.<p><pre><code> def rename_user(user_id: str, name: str) -&gt; User | Exception: # Consume the function user = get_user(user_id) if isinstance(user, Exception): return user user.name = name return user </code></pre> This is not Pythonic. Don&#x27;t do it. Like it or not, Python uses exceptions. How do I know that some other code that get_user calls isn&#x27;t going to raise an exception? What if the program receives an interrupt signal during the get_user call? When I&#x27;m writing Python code, I have to think about exception handling, and now when I use this library, I have to add a bunch of isinstance calls too?<p>Perspective: I&#x27;ve written primarily in Python for over 20 years, as well as coded extensively in many other languages (C, Objective-C, JavaScript, Java, Bash) and have familiarity with a bunch more (Go, Ruby, Gradle, TCL, Lua, Kotlin, C++).<p>In practice, exception handling, declared exceptions or not, just isn&#x27;t that big of a problem. When I&#x27;m writing code, I have to reason about it, and exceptions and return&#x2F;error values are just one aspect of that reasoning.
评论 #38207697 未加载
评论 #38207571 未加载
评论 #38207529 未加载
评论 #38207817 未加载
jmholla超过 1 年前
Why does the author want to swallow these exceptions? Let them propagate and it&#x27;s obvious where the issue lies. If you can&#x27;t handle an exception, don&#x27;t catch it.<p>&gt; It&#x27;s impossible to know which line might throw an error without reading the functions themselves... and the functions those functions call... and the functions those functions call. Some thorough engineers may document thrown errors but documentation is untested and therefore untrustworthy. Java is a little better because it forces you to declare uncaught errors in method signatures.<p>The author&#x27;s proposal doesn&#x27;t change this as much as they think it does. You still don&#x27;t know what type of errors a function will throw without inspecting the code and thus how to resolve them. Unless, you have a blanket switch for every possible error anything could return which is the very thing they are complaining about.
评论 #38207523 未加载
TrustPatches超过 1 年前
One problem I’ve experienced doing something like this is you end up with both exceptions and error values since the standard library and 3rd party libraries are still primarily exception based. You either have to live with it or create wrappers that catch errors and return them as values.
评论 #38207460 未加载
评论 #38207290 未加载
评论 #38207790 未加载
guitarbill超过 1 年前
&gt; Rust returns returns errors using a &quot;wrapper&quot; type called Result. A Result contains both a non-error value (Ok) and an error value (Err)<p>A `Result` can contain either a non-error value (Result::Ok) <i>or</i> and error value (Result::Err), never both.
评论 #38207600 未加载
anentropic超过 1 年前
&quot;How we made a non-idiomatic Python SDK for our app that Python devs will hate&quot;
评论 #38211057 未加载
klyrs超过 1 年前
Oh, good, heavyweight error handling just in time for py3.11&#x27;s zero-cost exception happy path.<p>But, more generously: why not simply return an error, and use isinstance(val, Error) for error handling? Making objects and calling functions is quite costly, and that can largely be avoided.
评论 #38207675 未加载
评论 #38207903 未加载
评论 #38207399 未加载
theamk超过 1 年前
I don&#x27;t understand why people insist that all errors must be handled all the time. It could be my C++ background, but I feel there are two very different errors:<p>Expected errors - like &quot;user not found&quot; - should use a value instead of exception. In Python, you can use sentinel objects, or tuples, or None.. lots of options really. Occasionally there is a good reason to use exceptions for flow control even for know errors (various hooks come to mind), but this should be pretty rare compared to number of places that can raise an unexpected errors.<p>Unexpected errors should not be caught at all, except maybe at the very top level (to record them and return 500 to user). The examples in post, where you catch exception and re-raise Exception back are terrible - what&#x27;s the point of them? There is no extra clarity, just verbosity. I would defect them in any code review.<p>Coarse-grained error handling is great as long as exceptions are meaningful and stack traces are good, which is the usual case in python. All that matters for unexpected errors is that (1) user sees an error message and (2) the real cause is recorded for later analysis. A single top-level try block does both.
评论 #38209632 未加载
txbuck超过 1 年前
Not necessarily advocating for unidiomatic python&#x2F;code, but you could use a decorator to automatically wrap the function call with a try-catch and package the return value appropriately. Lot less mangling of function bodies that way, just return and raise exceptions like normal. You *could* specify the expected Exception type, but considering the rest of the ecosystem probably won’t be following along with documenting expected exceptions, I assume it wouldn’t be worth it and would be more straightforward that all the exception types in the signatures be the plain vanilla Exception. Would also be super inefficient pre-3.11 but ¯\_(ツ)_&#x2F;¯
rednafi超过 1 年前
This doesn’t do much. Many of the stdlib functions will still raise exceptions. Also, just because you’re returning exception from a function doesn’t guarantee that something else won’t raise an error. This isn’t an issue in Go&#x2F;Rust since errors are treated as values in the core language and you’re forced to treat them so everywhere.
mmnfrdmcx超过 1 年前
I don&#x27;t agree with this post.<p>Engineering is about tradeoffs.<p>There is more advantage in doing the accepted python solution (exceptions) than inventing your own (which you claim to be better, but I personally think is worse). If you are developing in a team, stick to established conventions and spend your time focusing on your business problem.
kitd超过 1 年前
Quite apart from the Python discussion, the author captures why I prefer errors as values (a la Go) to exceptions (a la Java), and I have written both styles for many years.<p><i>&gt; Regardless of the specific approach, returning errors as values makes us consider all of the places an error could occur. The error scenarios become self-documenting and more thoroughly handled.</i><p>This is so true. Most Java exception handling is a try&#x2F;catch around about 20 lines of code, with superficial logging&#x2F;rethrowing and no context about exactly what was being done to what when the exception occurred, just a filename&#x2F;line# and a probably cryptic error message.<p>In Go, best practice is something like:<p><pre><code> bytes, err := os.ReadFile(&quot;myfile.json&quot;) if err != nil { return nil, fmt.Errorf(&quot;reading file %s: %v&quot;, &quot;myfile.json&quot;, err) } var data map[string]any err = json.Unmarshal(bytes, &amp;data) if err != nil { return fmt.Errorf(&quot;unpacking json from file %s: %v&quot;, &quot;myfile.json&quot;, err) } </code></pre> This gives you precisely targeted errors that tell exactly what you were doing to what. Your future self will thank you when you&#x27;re desperately trying to work out what went wrong last thing on a Friday.<p>If you are going to replicate this with exceptions, it would require much more boilerplate, as his example demonstrates, which is ironic given that is the charge levelled at Go.
评论 #38208089 未加载
评论 #38208216 未加载
ed_blackburn超过 1 年前
I&#x27;m six months into my Python journey. We aren&#x27;t building a library, so everything runs on 3.11. Having spent most of my career in statically typed and sometimes functional languages, I&#x27;ve found the result package approach and pattern-matching suggestion work well. There&#x27;s been a suggestion it&#x27;s not very Pythonic, but I&#x27;m willing to continue using a result monad because the trade-off is one-sided; it comfortably pays for itself.
评论 #38207370 未加载
demi56超过 1 年前
Let python be python, let Go be Go, let Rust be Rust it has never worked well for any language trying to be like another language
oDot超过 1 年前
In FileMonger[0], which uses Tauri, I have implemented a `Result` logic for errors in TS, similar to what&#x27;s available in Rust. It&#x27;s clunkier, but still much preferable to the mess of throwing. Much easier to handle errors and debug.<p>[0] <a href="https:&#x2F;&#x2F;filemonger.app&#x2F;" rel="nofollow noreferrer">https:&#x2F;&#x2F;filemonger.app&#x2F;</a>
评论 #38207259 未加载
评论 #38229121 未加载
Karellen超过 1 年前
&gt; So if we want to be really safe then we&#x27;ll wrap each call with a try&#x2F;catch:<p><pre><code> try: thing.set_name(&quot;Doodad&quot;) except Exception as err: raise Exception(f&quot;failed to set name: {err}&quot;) from err </code></pre> &gt; As we think about each possible error we realize that our original logic would crash the program when we didn&#x27;t want it to! But while this is safe it&#x27;s also extremely verbose.<p>How is this safer than the original?<p>If the caller wasn&#x27;t catching exceptions thrown by this function before, it&#x27;s not catching exceptions thrown by this function now. What is being gained by catching an exception to do nothing but throw another exception?<p>This feels like a strawman.
b3orn超过 1 年前
Nope, don&#x27;t like it. It&#x27;s also a little disingenuous to switch the example halfway through. Anyway, I fixed your code, with exceptions<p><pre><code> def get_user(user_id: str) -&gt; User: rows = users.find(user_id=user_id) if not rows: raise Exception(&quot;user not found&quot;) return rows[0] def rename_user(user_id: str, name: str) -&gt; User: user = get_user(user_id) user.name = name return user, None</code></pre>
sethammons超过 1 年前
python is where I learned to hate exceptions as control flow - Twisted is twisted. Go was such a breath of fresh air. Now I&#x27;m back in python primarily and I am constantly wondering what my functions actually take and actually return. Exceptions are just spooky GOTO and a distance. Our logs are littered with them and have to use Sentry to tell us &quot;oops, you introduced a new error path.&quot; Our builds are full of warnings and versioning issues. I&#x27;ve yet to see a decent sized python project that is not a mess.
评论 #38207643 未加载
TigerTeamX超过 1 年前
I love it. Recently been rewriting Goleko.com backend in Go from Python. The errors as value paradigm is so nice for 90% of the time. It is so much more robust code out of the bat.
评论 #38207498 未加载
jflakjwoasdlf超过 1 年前
&gt; tuple[User | None, Exception | None]<p>tuple[User, None] | tuple[None, Exception]
评论 #38208061 未加载
评论 #38208390 未加载
diarrhea超过 1 年前
As for helping the type checker, try typing’s TypeGuard. They help the type checker reason about situations such as “if this is None, this other thing is that”.