go 转 Python 的心智负担增加

10 天前
 yujianwjj

之前写 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 给我的感受就是,想写好一个健壮的程序,有很大的心智负担,我总是要考虑我调用的函数会不会有异常。

8052 次点击
所在节点    Python
96 条回复
aababc
10 天前
啊,是这么处理吗,我都是在入口处理,内部基本都不捕获异常
peteretep
10 天前
糙猛快的开发不需要考虑异常
povsister
10 天前
你这么严谨不适合写 python (狗头
streamrx
10 天前
用 try
wefgonujnopu
10 天前
python 动态类型确实不适合写大项目,异常的话,如果数据格式确保百分百不会问题,就不需要处理,如果是 IO 函数,处理文件 IO 或者网络 IO ,统一 try,一般出现错误的基本都是这些操作
codersdp1
10 天前
写奔放些
iorilu
10 天前
你可以截获不同的具体异常阿

try:

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

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

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


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

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

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

如果希望严谨处理,你应该看 Rust 之类的有强错误标记的语言,或者等等接下来的 Kotlin 2.4 。
pollux
9 天前
自己写一个装饰器做异常捕捉
```
#!/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'

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1140619

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX