yujianwjj
V2EX  ›  Python

go 转 Python 的心智负担增加

By yujianwjj at 2025 年 6 月 24 日 · 12287 次点击

之前写 go ,go 调用函数的时候,有问题就是通过 返回值 有没有 err 来判断。心智负担很小,直接撸就行。

一个简单的案例,打开文件,然后 json 解析。 go 版本是

func TestA(t *testing.T) {
	fd, err := os.OpenFile("a.txt", os.O_RDWR, 0666)
	if err != nil {
		fmt.Println("打开文件失败", err)
	}
	defer fd.Close()

	var data map[string]string
	err = json.NewDecoder(fd).Decode(&data)
	if err != nil {
		fmt.Println("解析文件失败", err)
	}
	fmt.Println(data)
}

但是到 python 这边

f = open("a.json")
data = json.load(f)
f.close()

但是吧

  1. 如果文件不存在需要处理
  2. 文件存在,open() 执行异常了要处理
  3. json.load() 会不会异常?我跳转源码看 josn.load()源码也没看到他会返回哪些异常信息。

所以我写出这种代码

try:
	with open("a.json", "r") as f:
		data = json.load(f)
except Exception as e:
	print(e)

但是这样把多种异常合到一个 Exception 了,如果出现异常,你不知道是哪个函数调用出现的异常。所以就需要这样。

try:
	with open("a.json", "r") as f:
    	try:
			data = json.load(f)
    	except Exception as e:
			print(e)        
except Exception as e:
	print(e)

然后我发现,最大的问题就是,我每次调用一个外部函数的时候,TMD 根本不知道这个函数会不会异常,总不能每个函数调用都用 try/except 处理一下?

try:
	f1()
except Exception as e:
	print(e)
    
try:
	f2()
except Exception as e:
	print(e)
    
try:
	f3()
except Exception as e:
	print(e)

写 python 给我的感受就是,想写好一个健壮的程序,有很大的心智负担,我总是要考虑我调用的函数会不会有异常。

第 1 条附言  ·  2025 年 6 月 24 日
try:
f1()
f2()
except A as e:
...
except B as e:
...

这个用法我知道,但是他存在一个问题就是 如果 f1 和 f2 都返回同一个类型的异常 A 的时候,这样捕获不知道是哪个函数返回的。
第 2 条附言  ·  2025 年 6 月 24 日
with 外面再加一个 try 的原因是,如果 open 的文件不存在,还是会报异常的。with 的作用只是 帮你自动 close() 文件,不需要像 go 那样用 defer close 。
第 3 条附言  ·  2025 年 6 月 24 日
ry:
...

except TypeRrror:
....
except AtributeError:
...
except ValueError:
....

这个方案比较头疼的是,我不知道我调用的函数会返回什么异常,很多时候,我跳转到函数的源码里面,也看不出会返回什么异常。
第 4 条附言  ·  2025 年 6 月 25 日

看了大家的讨论,基本意见就是 对于想要特殊处理的异常就 catch 该异常进行处理,最后加一个兜底的 Exception。 但是这个方案似乎还是有个缺点:

try:
    f1()
    f2()
except A as e:
    ... # 特殊处理
except B as e:
    ...
except Exception as e:
    traceback.format_exc()

我希望对 f1() 抛出的 A 异常进行特殊处理。但是这种写法,有可能是 f1() 没有抛出 A 异常,是 f2() 抛出的 A 异常,这样逻辑就不对了。代码需要写成下面这个样子。

try:
    try:
        f1()
    except A as e:
        .... # 特殊处理
    f2()
except A as e:
    ...
except B as e:
    ...
except Exception as e:
    traceback.format_exc()

好像缺点就是代码丑点,其他没啥问题。跟 go 的 if err != nil { return err } 半斤八两,都挺丑的。

另外还有个问题就是: 没有办法知道一个 python 函数会不会返回异常,除非是自己写的一些非常明确的函数,我确认他没有返回异常。但是实际业务中,肯定是大量调用库函数,总感觉写的每个 python 函数,都要加个 try/except .

def a():
    try:
        ...
    except :
        ....
99 条回复  •  2025-07-16 09:31:34 +08:00
aababc
   1
aababc  
   2025 年 6 月 24 日   ❤️ 1
啊,是这么处理吗,我都是在入口处理,内部基本都不捕获异常
peteretep
   2
peteretep  
   2025 年 6 月 24 日
糙猛快的开发不需要考虑异常
povsister
   3
povsister  
   2025 年 6 月 24 日 via iPhone   ❤️ 53
你这么严谨不适合写 python (狗头
streamrx
   4
streamrx  
   2025 年 6 月 24 日 via iPhone
用 try
wefgonujnopu
   5
wefgonujnopu  
   2025 年 6 月 24 日
python 动态类型确实不适合写大项目,异常的话,如果数据格式确保百分百不会问题,就不需要处理,如果是 IO 函数,处理文件 IO 或者网络 IO ,统一 try,一般出现错误的基本都是这些操作
codersdp1
   6
codersdp1  
   2025 年 6 月 24 日
写奔放些
iorilu
   7
iorilu  
   2025 年 6 月 24 日   ❤️ 1
你可以截获不同的具体异常阿

try:

except A as e:
...
except B as e:
...
cdwyd
   8
cdwyd  
   2025 年 6 月 24 日 via Android
实际项目中代码洁癖不可取,while True try 结构相当稳定,finally 语句里面再加个状态检查 “重启”的操作,虽然代码丑但是不容易崩。
kdwnil
   9
kdwnil  
   2025 年 6 月 24 日 via Android
在外面套一个大的 try catch 就好,go 那一堆 err!=nil 我写多了还是觉得有点啰嗦了
sss393
   10
sss393  
   2025 年 6 月 24 日   ❤️ 1
我感觉 go 的写法挺好的,好几年前写前端的时候,也会把 trycatch 改造成 const [err, res] = xxx 这种写法,比 trycatch 嵌套好用多了
wyntalgeer
   11
wyntalgeer  
   2025 年 6 月 24 日   ❤️ 2
@iorilu 这 OP 基础用法不看,选择来发帖……
mdn
   12
mdn  
   2025 年 6 月 24 日
语言习惯问题
BBCCBB
   13
BBCCBB  
   2025 年 6 月 24 日
```go
f err != nil {
fmt.Println("打开文件失败", err)
}
```

这里有 err 还继续执行后续的解析, 逻辑就不对? 要么跳过解析, 要么直接 return.

如果是直接 return, 在 python 里抛异常直接就跳回去了, 只需要在外层加 try catch 就行了. 不需要每个地方都 try catch, 但 go 不行, 每个地方都得写.


只有在跳过解析或者你要在打开失败做一些操作, 比如忽略报错的时候, 才需要在 open 加 try catch.
zjengjie
   14
zjengjie  
   2025 年 6 月 24 日   ❤️ 1
打印个 "打开文件失败" 就叫处理异常吗,你的 go 代码里前面都失败了还在往后走呢。一般这类错误本来就不用管,直接看程序打印的异常堆栈就知道那行出错了。大型项目一般都有全局异常处理,根据异常类型统一处理和返回,写的时候除非特殊情况要处理,一般也不需要太关注,最多就转成个自定义 exception 抛出去就好了。
noahliaszn
   15
noahliaszn  
   2025 年 6 月 24 日
不想要心智负担 就不要类型检查(doge 看看 rust 你可能心智负担更严重 和编译器做斗争哈哈😄

另说一句可以捕获不同的自定义 exception 在一行
https://docs.python.org/3/tutorial/errors.html#handling-exceptions
GeruzoniAnsasu
   16
GeruzoniAnsasu  
   2025 年 6 月 24 日   ❤️ 2
用法是错的,心智负担增加是对的。python 的感觉大概是谁来都能写成狗屎,go 的感觉大概是拴条狗来都能在屎上继续写
tf2
   17
tf2  
   2025 年 6 月 24 日
try:
iiiiii
jjjjjj
except 文件挂了
xxx
except 解析出错
yyyyy
except 其他挂了
zzzzz
aloxaf
   18
aloxaf  
   2025 年 6 月 24 日
话说你 Go 这里面的处理方式也不对啊,你打印了错误,结果继续往下执行了?
你应该打印后直接上抛,放在 Python 里就相当于什么都不处理,在上层捕获再打印错误。
w568w
   19
w568w  
   2025 年 6 月 24 日   ❤️ 1
这俩语言都是用来快工出糙活的。

不是说你考虑错误处理不对,而是语言设计者就不希望你这么写,最自然的方式就是 let it crash 。

如果希望严谨处理,你应该看 Rust 之类的有强错误标记的语言,或者等等接下来的 Kotlin 2.4 。
pollux
   20
pollux  
   2025 年 6 月 24 日   ❤️ 1
自己写一个装饰器做异常捕捉
```
#!/opt/python3108/bin/python3.10
from functools import wraps

def catch_specific_exceptions(func):
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"捕获到异常: {e}")
return None
return wrapper


@catch_specific_exceptions
def specific_operation(x, y):
return x / y

@catch_specific_exceptions
def read_file(file):
f = open(file)
data = json.load(f)
f.close()

specific_operation(10, 0)
read_file("x.json")
```

捕获到异常: division by zero
捕获到异常: [Errno 2] No such file or directory: 'x.json'
cloudzhou
   21
cloudzhou  
   2025 年 6 月 24 日
这就是经典的 error vs exception 争议
Sawyerhou
   22
Sawyerhou  
   2025 年 6 月 24 日
go 的异常处理比较特殊,除非你不想学其他语言,否则走出舒适圈是不可避免的。
Lockroach
   23
Lockroach  
   2025 年 6 月 24 日   ❤️ 1
fd, err: xxx
if err != nil
这样的行为,和 try: ... except Exception: ... 似乎也没什么区别,都是捕获一个笼统错误
如果要捕获精确错误,应该有精细化的 Exception 实例
iyaozhen
   24
iyaozhen  
   2025 年 6 月 24 日
大家不要纠结于楼主的 print 嘛 只是示例

这个其实就是经典的错误处理之争,要是有定论,go 早就采用了

其实大家写 python 基本也不处理异常,触发非常特殊的地方。不然就是最外层一个 try catch ,至于错误类型,会打印出来的,也有堆栈
go 也有 go 的问题,除了繁琐(这可能优点),另外就是 err 往上抛,最外层不知道哪里错了(当然有各种解决办法)
uds9u32br
   25
uds9u32br  
   2025 年 6 月 24 日   ❤️ 1
同感,陆陆续续几年写了点 python ,写的挺烦的。
zoharSoul
   26
zoharSoul  
   2025 年 6 月 24 日
肯定在最外层统一处理啊
go 那种一行一判断麻烦的要死
sagaxu
   27
sagaxu  
   2025 年 6 月 24 日
你看看错误处理代码,下面两种占多少
1. 记录 error ,并且把 error return 给调用者
2. 直接把 error return 给调用者

很多时候我们不关心每个具体错误,只是在某个地方记录出错的调用栈和位置和一个简单的描述,此时 exception 就是更简单的选择。用 panic-revover 模拟 try-catch 的代码没少见吧?
ksedz
   28
ksedz  
   2025 年 6 月 24 日   ❤️ 1
python 一般都是运行脚本,异常会精确定位到行,所以不会有你说的 debug 问题。
因此,python 操作上尽量不要 try except ,即便使用,在不能完全消化错误的时候也要打印原始异常调用栈。
ajunno
   29
ajunno  
   2025 年 6 月 24 日   ❤️ 1
python 有个用装饰器代替 try...catch...代码块的库 merry https://merry-py.readthedocs.io/en/latest/quickstart.html#getting-started
jqtmviyu
   30
jqtmviyu  
   2025 年 6 月 24 日   ❤️ 1
对 py 项目的糟糕印象来自某个几 k stars 的项目, 工程化处于能跑就行, 依赖管理就一个 requirements.txt requirements-dev.txt
代码里类型乱传, 有时数组 有时非数组. 有时可以整数 有时可以小数. 遇到异常整个程序就挂了.
coderluan
   31
coderluan  
   2025 年 6 月 24 日   ❤️ 1
都没说到重点吧,python 的 with 本身就是解决文件异常的问题,也就是 with open 就不用加 try 了,也就是这个代码在 json.load 加 try 就行了。

至于后面有多个函数的情况,比如 f1 ,f2 ,那么在最开始的时候加一个 try ,想知道的具体哪个错了,应该在 except 的时候输出下 traceback 。
keenkiller
   32
keenkiller  
   2025 年 6 月 24 日   ❤️ 1
fast fail

外围加一个大的 try...except 就行
Rorysky
   33
Rorysky  
   2025 年 6 月 24 日
just let it fail
coderluan
   34
coderluan  
   2025 年 6 月 24 日
except Exception as e:
print(e)
traceback.print_exc()
arischow
   35
arischow  
   2025 年 6 月 24 日
https://docs.python.org/3.12/library/json.html#json.load

> If the data being deserialized is not a valid JSON document, a JSONDecodeError will be raised.
shinession
   36
shinession  
   2025 年 6 月 24 日
只要 try 一次就行了, 异常类型可以判断, 也可用 traceback 解析, OP 这是没入门就来找茬
DonaldVVV
   37
DonaldVVV  
   2025 年 6 月 24 日
try
exception exception as e:
print(f'{e!r}')

一个 print ,会把错误堆栈都打印出来,不管什么错误。跟 go 那个就差不多了
Donahue
   38
Donahue  
   2025 年 6 月 24 日
为什么要处理异常,有问题了直接看报错 debug(笑)
python 感觉不适合用来写太严谨的代码,会很麻烦
deplives
   39
deplives  
   2025 年 6 月 24 日 via iPhone
菜就多练 就举的这个例子的代码 都不想吐槽
用了 with 还在外面包 try 那你猜 with 是干啥的
还有 json 有一个方法教叫 loads 可以了解一下,下次真要喷 找个合理的例子
Gilfoyle26
   40
Gilfoyle26  
   2025 年 6 月 24 日
python 还需要异常处理。。。。。我都是写脚本,用完就弃。
Vegetable
   41
Vegetable  
   2025 年 6 月 24 日
相比于 Go, Python 确实存在意想不到的报错这种情况。健壮的 Python 代码来自于经验,老练的 Python 使用者熟知常用库和方法会出现什么问题,哪里需要处理异常,并将异常融入自己设计的控制流。

所以 Python 写好并不容易,Go 的异常模式确实有其优势,虽然更多是被批评,但也看和谁比。
blockmin
   42
blockmin  
   2025 年 6 月 24 日
建议转别的语言,Python 就是一通莽,快就完事了,什么后果先不要管
sazima
   43
sazima  
   2025 年 6 月 24 日
try:
...

except TypeRrror:
....
except AtributeError:
...
except ValueError:
....
idealhs
   44
idealhs  
   2025 年 6 月 24 日
try catch 都不会写,你这是 go 和 python 的问题?很怀疑你是不是只会 go
sky3hao9
   45
sky3hao9  
   2025 年 6 月 24 日
用惯了 GO, 说实话, 再看 Java, py, php 这些, 就跟看见屎粑粑一样
yingxiangyu
   46
yingxiangyu  
   2025 年 6 月 24 日
logging.exception(e) 会把完整的调用栈都打印出来
qiuhang
   47
qiuhang  
   2025 年 6 月 24 日
我看你不过是困在 go 里面还没出来罢了,说来说去你这不就可能存在 3 个异常吗?文件不存在,文件没法读取,json 解析异常,对应你 go 的逻辑,你这么写不就行了?

import json, os
filename = 'a.txt'
if not os.path.exists(filename):
raise Exception('文件不存在')

try:
with open(filename) as f:
json.load(f)
except Exception as e:
raise Exception(f'解析文件失败 {type(e)}')

或者你实在是要求细致到每一种异常,那你统一去 except 里面逐个处理不就行了

import json, os
filename = 'b.txt'
try:
with open(filename) as f:
json.load(f)
except Exception as e:
if isinstance(e, FileNotFoundError):
raise Exception('文件不存在')
elif isinstance(e, PermissionError):
raise Exception('...')
elif isinstance(e, json.decoder.JSONDecodeError):
raise Exception('...')
else:
raise Exception('...')
darksword21
   48
darksword21  
   2025 年 6 月 24 日
同感,所以每次想到那帮提案把 try cache 加到 go 里的人是不是脑子有什么大病

还有说“你可以截获不同的具体异常阿”

那么我怎么知道都有什么类型的异常呢?当前确实可以去源码里找,但是这和楼主说的“TMD 根本不知道这个函数会不会异常”是一个问题,可以说是心智负担+心智负担,相比之下明确返回 err 并在注释 doc 写上都可能有什么样的异常是最省心的
edisonwong
   49
edisonwong  
   2025 年 6 月 24 日
前司有个项目,一个函数里不同阶段的 return 结构不一样,有时候是 string ,有时候是 tuple
现在只有快写脚本我是用 py 的,哈哈哈哈
lcvs
   50
lcvs  
   2025 年 6 月 24 日
你太严谨了,有问题就应该暴露问题,只用 try except 包住最外面那层就行了
NoOneNoBody
   51
NoOneNoBody  
   2025 年 6 月 24 日
脚本语言最大优势就是随时改,不用全部编译,尤其是调参脚本,谁会 ratio 改个 0.01 重新编译一遍啊
所以没必要的情况下不必写 try...except 容错,直接让它报错还更清晰(直接就显示哪一行出错)
try...except 更多是有两种方案时,此路不通换另一条,或者某些问题不重要,出错也可以 pass ,节省时间

初学的时候,确实对出错很敏感,但 python 写多几年就知道了,只要不是数据改动大,或者跑几小时的项目,报错不必紧张,及早发现比产出时报错好得多,不宜太早写 try
python 需要写容错的地方确实太多了,会的人知道 try...except 就是“掩饰”用的,产品真不适合给小白用户
redbule
   52
redbule  
   2025 年 6 月 24 日
半斤八两吧,判断 err 和 try catch 我感觉都差不多,都挺影响读代码的
好的库应该尽量不抛出错误,因为你都处理不了还指望使用者处理? --《软件设计的哲学》
zonde306
   53
zonde306  
   2025 年 6 月 24 日
两者设计思路不一样,不能直接套用

在传统的异常处理里面,不需要考虑这么多东西,避免心智负担
异常这种东西,如果处理不了,那就不要处理,就直接让它抛出,交给上一层
上一层决定是放弃,还是重试,又或者不处理
不行就直接 crash

例如打开文件时文件不存在,文件不存在不好处理,直接 crash 损失更小,避免错误执行
user1284
   54
user1284  
   2025 年 6 月 24 日
费这功夫, ai 一秒给你全写完了, 感觉 py 的补全是很快的, 你完全可以不写任何异常, 最后直接让 ai 给你补上就行了
smlcgx
   55
smlcgx  
   2025 年 6 月 24 日 via iPhone
都用 with 了没必要写 try 了吧,除非你想把异常捕捉打印出来,如果自己调试直接看报错就行了
henix
   56
henix  
   2025 年 6 月 24 日
我写 python 的时候大多数情况下都不用像 go 一样细致地处理异常
通常是不处理或者最外面一层 try catch 就完事
不知道抛什么异常,就等运行的时候报错了记录下来
hingle
   57
hingle  
   2025 年 6 月 24 日
异常太多,只处理想处理的,其他的统一或全局处理或不管。

比如 Open ,会出现文件不存在、权限不足等各种错误,如何这些错误是业务需要,那就去处理。

“健壮的程序”,也只是相对的,在 go 的 json 序列化和反序列化里,甚至会 panic ,不可能每次都去 recover 。
simple2025
   58
simple2025  
   2025 年 6 月 24 日
我还是喜欢 python 这种异常,毕竟大部分异常我只能上抛,那为什么不让程序帮我上抛?
simple2025
   59
simple2025  
   2025 年 6 月 24 日
@DonaldVVV 居然还有这种东西?
simple2025
   60
simple2025  
   2025 年 6 月 24 日
我就不懂了?

python 里面你确实不知道发生了什么异常?难道 golang 里面你就知道什么 error 了吗?那不相当于 java 的 check error 了吗?

java 的 checkexception 不是已经证明是个 SB 了吗?
Leviathann
   61
Leviathann  
   2025 年 6 月 24 日
@w568w 已经确认在 2.4 加上 union error 了吗
w568w
   62
w568w  
   2025 年 6 月 24 日   ❤️ 1
@Leviathann KotlinConf 2025 说的,到 2.4 应该还是 experimental 。

X 帖子: https://x.com/joreilly/status/1925451874116817181
Leviathann
   63
Leviathann  
   2025 年 6 月 24 日
@chenqh checked exception 本意是好的,只是编译器写的太低级没做到自动推导
wulili
   64
wulili  
   2025 年 6 月 24 日   ❤️ 1
还是写 C#最省心,每个函数会不会抛出 Exception ,还有会抛出什么类型的 Exception 都给你列的明明白白的,很直观。
lance07
   65
lance07  
   2025 年 6 月 24 日
go 不就是"调一个函数处理一次 "
hwdq0012
   66
hwdq0012  
   2025 年 6 月 24 日
python 的异常可以把 stacktrace 打印出来看看,就知道哪里异常了,用返回值确实挺好,c++很多人宁愿用返回值不用 exception
johnnyyeen
   67
johnnyyeen  
   2025 年 6 月 24 日
python 的思维逻辑很可以“曾智慧” doge
yiwayhb
   68
yiwayhb  
   2025 年 6 月 24 日
@wulili 实际上,只有 MS 官方的库有这种良好的文档注释,更多的第三方库都不太完善。
常用的做法仍然是「 let is crash 」,只处理能解决的异常,最外层统一处理,给出用户交互
bronyakaka
   69
bronyakaka  
   2025 年 6 月 24 日
你都文件不存在了还 return 啥,打印啥,有意义吗?这时候是要主动抛出问题

python 直接不处理让他自己报错就行了,报错自带堆栈和 return ,一眼就知道问题了

go 不得不写 err ,是因为 go 没有异常传播机制,只能手打 err ,不然会继续往下走,非常蠢
newtype0092
   70
newtype0092  
   2025 年 6 月 24 日
不是精细到每一个异常都处理才是好的设计,不然为什么系统要分那么多层级。

try catch 是在理清楚哪些错误需要处理,哪些错误需要屏蔽的基础上再进行 fallback 处理的,目的是保证程序能按预期执行下去。

一般好的设计会把所有的下层异常都包装成自己本层可解释的异常,声明在方法上。
当然也有很多没有这么做的,就会冒出没有声明的异常,这种情况如果没有特殊的原因的话做统一处理就好了,实在需要某些信息的时候就往下追追代码。

对于你说的不知道有哪些异常的问题,先学会看文档吧,一开始就追代码容易追不对地方,基础库的文档还是比较全的,熟练了想再追代码的事。
rockdodos
   71
rockdodos  
   2025 年 6 月 24 日
python EAFP ,外层 try 就完事了,我觉得 go 才罗里吧嗦的,一直 if err != nil
xman99
   72
xman99  
   2025 年 6 月 24 日
php 可记录调用栈信息的,会有报错行数
不知道 python 有没有对应处理方法
AV1
   73
AV1  
   2025 年 6 月 24 日   ❤️ 3
自己封装一个嘛,反正 python 那么灵活:

from typing import Callable, Tuple, TypeVar

T = TypeVar('T')
def go_try(fn: Callable[[], T]) -> Tuple[T, Exception]:
▓▓"""go 式异常"""
▓▓try:
▓▓▓▓return (fn(), None) # type: ignore
▓▓except Exception as error:
▓▓▓▓return (None, error) # type: ignore

# 回来了,一切都回来了🐶
myfile, err = go_try(lambda: open('a.json'))

# 就是这个味🐶
if err is not None:
▓▓print('open 异常', err)
superrichman
   74
superrichman  
   2025 年 6 月 24 日   ❤️ 2
@qiuhang 异常可远不止这些,光是文件读取相关的异常就能列出一长串:

文件不存在异常
传入路径是文件夹而非文件
没有读取权限
读取模式参数错误
使用错误的模式操作文件,比如以读模式尝试写入
各种 OS 级异常,比如磁盘损坏、挂载分区断开等
文件编码错误,比如用 UTF-8 解码 GBK 文件
等等等等,遇到得多了你会发现奇葩异常真不少。

如果每个异常都要手动处理一遍,代码会变得又臭又长,简直跟 Go 一样,心智负担爆表。

一个 try-catch 包住,已经能兜住大部分问题。只有那些频繁出现且确实值得特殊处理的异常,才需要单独写逻辑去应对。否则就是浪费时间,拉低可维护性。
UN2758
   75
UN2758  
   2025 年 6 月 24 日
@DonaldVVV 你这只打印了异常类型,没输出异常的代码行数,还不如 traceback.print_exc() 呢
iyaozhen
   76
iyaozhen  
   2025 年 6 月 24 日
@superrichman 是的,异常可多了。之前写 Python 就是,压根不告诉你会返回哪些异常
XueXianqi
   77
XueXianqi  
   2025 年 6 月 24 日
@DOLLOR 嘿,你别说,你还真别说,就是这个味儿!
ychost
   78
ychost  
   2025 年 6 月 24 日
写 python 就不需要每个函数都处理 err 了,像 java 一样,需要处理的地方才 catch
wx497657341
   79
wx497657341  
   2025 年 6 月 24 日   ❤️ 1
go 没有资格拿异常处理来碰其他语言
openmynet
   80
openmynet  
   2025 年 6 月 24 日
python: 默认一切都安全的
rust: 默认一切都是不安全的

使用 python 就是要放下一切,能跑就行。
freemoon
   81
freemoon  
   2025 年 6 月 24 日
楼主你提出的是一个经典的语言设计中的 error 处理方式问题,可以去 google 搜一下各语言的 error 设计思想。具体选择真的是看自己喜好了
cloudzhou
   82
cloudzhou  
   2025 年 6 月 24 日
@wx497657341 go 压根没有 “异常处理”,除了一个 defer ,何来 “碰”

这是一个经典的 error vs exception 的错误处理两种方式
go 作者专门写了一个文章解释 https://go.dev/blog/errors-are-values

对我来说,因为有 Java 、Go 的经验,很理解两种方式为什么都存在

当需要非常严谨代码,同时需要记录具体在哪里中断的时候,Go 的每一次处理 error 就很有效果,讲究“立刻处理错误”
当只需要全局性的 try catch 然后抛出一个业务错误,不关注具体哪里出错了,异常非常有用
wuhunyu
   83
wuhunyu  
   2025 年 6 月 24 日
现在应该就三种异常处理方式吧
1. try-catch:以 java ,python 等语言为代表,应该是大部分语言的选择
2. 返回错误:以 go ,c 为代表
3. 强制处理错误:以 rust 为代表
其实写多了 java 这样的,对于一些第三方库的方法,都是直接捕获 Exception 异常的。对于必须要处理的异常,像是 go 这样显式返回错误的处理方式还挺直观的。但如果说能够明确不会发生错误,那还是 java 这种 catch 的方式好,代码会简洁很多。至于 rust 的处理,对于我这种只使用 java ,python 和 go 的开发者来说,有点过于繁琐了
crackidz
   84
crackidz  
   2025 年 6 月 24 日
写脚本需要看你使用的库代码质量和文档怎么样,否则很容易转角遇到惊喜,各种意义上的惊喜

我很想吐槽,很多库的作者其实工程意识不强,哪怕常见的库都有各种各样神奇的神奇 bug 。这种问题在前端库和 Python 之类的库都是很常见的问题,你甚至能在使用非常广泛的库中发现神奇的泄露等等 bug ,几年都不处理挂在那。至于那种 Catch 了之后不抛新异常或者不返回出来更是很多作者会干的事,给你打印了个日志完事...

当然,这些槽点不是这些语言生态特有的,是比较常见的开源库通用问题了...有些时候上生产,不乱用开源库是一个技术活,如何做好监控和故障重现都很需要好的开发者和 SRE 后面盯着。实话实说,这类问题一般在大家经常吐槽的 Java 和 Go 项目中处理起来稍微简单一些,一般这些的项目工程配置比较完善,即便出现定位也相对容易一些
crackidz
   85
crackidz  
   2025 年 6 月 24 日
@crackidz 另外补充一下 OP 提到的一些具体问题,首先大概可以确定 OP 没读 Python 的官方文档。Python 的官方文档其实这方面做的比较好的典型,会明确对应的异常,比如你提到的 https://docs.python.org/3/library/json.html#json.load 当然,Python 其实历史项目比较久,有些文档属于上古时代的,所以不代表所有的都会有完善的记录和统一的格式
nlimpid
   86
nlimpid  
   2025 年 6 月 24 日
我对 Python 也不是很熟悉,不过我还是认为 Python 的错误处理更好些。

1. Go 的这种显式的把 Err 当成返回值的设计选择会让代码变的啰嗦一些。对于题主的例子来说,Python 生态可以根据不同的场景选择每一次处理都抛异常或者把异常合并在一起,让 Happy Path 更加清楚。

如

```
try:
result = foo()
do_something(result) // 这里也可以每次都 try ,和 Go 就一样了。
except FooError as e:
```

2. 我认为题主的这句话「很多时候,我跳转到函数的源码里面,也看不出会返回什么异常」是因为对语言熟悉程度导致的。我常写 Go 就知道常见的 io.EOF, os.ErrNotExist 。但从实际文档来看可能差异不大,以 JSON 为例,Python Doc 把 Exception 都放一起来相对来说还好找些。https://docs.python.org/3/library/json.html#exceptions https://pkg.go.dev/encoding/json#MarshalerError
ipwx
   87
ipwx  
   2025 年 6 月 24 日
楼主只要把 go 里面所有


if err := xxx(); err != nil {
return err
}

的地方全换成朴素的 xxx() 就对了。

====

然后当然也不需要

if err := xxx(); err != nil {
log.Formatf("xxx: %v", err)
return err
}

因为 python err 自动带堆栈信息。

====

总结来说就是,只要不是需要对 err 进行恢复的地方,一律就不要做 try ... catch ...
IurNusRay
   88
IurNusRay  
   2025 年 6 月 24 日
如果你想捕获特定异常,那就写多个 except, 如果你只是单纯的想在出现异常的时候是哪个函数、哪一行报的错,那就在 except 里面 print(traceback.format_exc()), 这样会把整个异常出现的链路打印出来,具体到每一行
Zy143L
   89
Zy143L  
   2025 年 6 月 24 日   ❤️ 1
..这 处理几个常见的异常主动抛出就行了 其他没碰见的问题直接全局 try 兜底不就行了
fbichijing
   90
fbichijing  
   2025 年 6 月 24 日
每一种语言有每一种语言的可取之处,它们射程不同,生态也不一样。
如果你所熟悉的 go 语言通杀一切,你也不必学习 python 。
如果说你刚才的目的是解析一个 json 文件,也就是原料就是文件,而目的就是将它解析成某种编程语言中的变量或者对象,方便操作。而这个过程,每种能处理这种操作的编程语言都有各自不同的表现形式。而“异常”或者“错误”,难道不是说法不同而已吗?它们都要面对:
1. 文件不存在
2. 文本编码不对
3. 文件本身的格式有问题
...
而这些需要共同面对的东西,你的 go 代码中,也只是将信息打印出来。(将有问题的信息打印出来你称之为健壮)。而每种能做这件事的编程语言,基本都有对应的捕捉这种信息的方式(行为),只是它们的代码表现有所差异而已。在我看来,捕捉这些信息是为了修复,而不是 go 语言捕捉的方式更优雅,更好看。这种事情一般有着先入为主的思想在里面,每个人的观念也有所不同。而太过于关注这个的话则忽略了主要目的,你只是想将文件正确解析出来。而输出的错误或者异常信息,它们也只是让你更好修复这些你意料之外的情况罢了。
如果你想看到整个过程中可能出现的问题,你在外层一个 try except ,然后把堆栈信息打印出来不就好了?捕获特定异常的话,一般是为了程序能继续跑。而如果是意料之外的异常,多半还是用 traceback.print_exc() 这种方式更加合适,否则都没有足够的错误信息。
------
我在学 go 中——基于某些原因——也没求一定要有什么结果。python >> go
XWZCoffee
   91
XWZCoffee  
   2025 年 6 月 24 日
我就想问一下,你写 ts 难道不跟 py 一样吗,不一样都是 Error ,然后你需要定义自己的 Error ,比如 AError extends Error,然后判断抛出来的 error 是什么 error ,instanceof 判断。
fox0001
   92
fox0001  
   2025 年 6 月 25 日 via Android
从 Java 过来就容易适应了🐶
sardina
   93
sardina  
   2025 年 6 月 25 日
你写的 go 代码也没处理打开文件时的特定异常,在 py 里咋就介意了
ZX576
   94
ZX576  
   2025 年 6 月 25 日
满篇的 try...except 不可取,最佳实践是

1. 如果函数出错,需要直接中止,直接在最外层捕获,统一处理,这一层你还可以加上监控之类的功能
2. 如果函数出错,可以跳过接着运行,写一个装饰器,比如叫 skip_when_met_error ,签名设计成能传入诸如 default 值这种


这样,你的业务逻辑只用考虑最正常的方式,写起来会可读很多
xiaoming1992
   95
xiaoming1992  
   2025 年 6 月 25 日
说实话没看出下面两种有什么本质区别,
// golang
res, err := func()
if err != nil {
__// ...
}

// js
try {
__res = func()
} catch (e) {
__// ...
}
无非是 golang 倾向于:每个错误都是重要的,都需要显式处理(或返回给上一层);
而一些语言认为很多错误无需关注,只需要往外抛(你只需要 catch 你关注的)。
mayli
   96
mayli  
   2025 年 6 月 26 日
的确,go 其实没有所谓的 python 的异常
要是真企业级,其实 java 做的比较好,调用一个函数,这个函数会抛出哪些异常都很明确,没处理直接告诉你

但是 py 这种动态语言,type hint 又没有所谓的`throws`,就没法准确描述调用代码可能出现的情况。

大概是一种平衡?专心于能跑就行 vs 完备的处理全部的情况。
chimission
   97
chimission  
   2025 年 7 月 16 日
楼主可以这么想,go 里你 if err!=null 如果命中了就打印一下错误信息退出了, 而在 python 里如果不加 try except 捕获错误也是直接退出, 不同的是 python 退出报错会自己打印完整的堆栈,可以精准的定位到错误代码, 不像 go 如果 crash 打印的堆栈信息杂乱, 所以这两个语言对于错误处理哲学是不一样的, 很多时候 pyhton 语言不需要强加 try except 捕获错误,除非 python 代码里想要在报错之后继续运行下去才会加 try except
chimission
   98
chimission  
   2025 年 7 月 16 日
所以楼主举的例子里,gi 语言在打开文件的时候要检查 err != null 不然继续执行下面的代码会有可能报错 crash ,而且报错信息很模糊定位困难。
但是在 python 里就不需要了,文件不存在报错退出就好了,报错信息比自己 print 的还详细
chimission
   99
chimission  
   2025 年 7 月 16 日
python 里不要一直想着捕获错误, 只有需要在错误发生之后还需要继续往下执行的时候才需要 try except , 如果不需要往下执行,正常报错退出即可
推荐学习书目
› Learn Python the Hard Way
Python Sites
› PyPI - Python Package Index
› http://diveintopython.org/toc/index.html
› Pocoo
值得关注的项目
› PyPy
› Celery
› Jinja2
› Read the Docs
› gevent
› pyenv
› virtualenv
› Stackless Python
› Beautiful Soup
› 结巴中文分词
› Green Unicorn
› Sentry
› Shovel
› Pyflakes
› pytest
Python 编程
› pep8 Checker
Styles
› PEP 8
› Google Python Style Guide
› Code Style from The Hitchhiker's Guide
© 2026 V2EX · 152ms · 3.9.8.5