V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
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
yujianwjj
V2EX  ›  Python

go 转 Python 的心智负担增加

  •  3
     
  •   yujianwjj · 17 天前 · 8326 次点击

    之前写 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 条附言  ·  17 天前
    try:
    f1()
    f2()
    except A as e:
    ...
    except B as e:
    ...

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

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

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

    看了大家的讨论,基本意见就是 对于想要特殊处理的异常就 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 :
            ....
    
    96 条回复    2025-06-26 00:42:56 +08:00
    aababc
        1
    aababc  
       17 天前   ❤️ 1
    啊,是这么处理吗,我都是在入口处理,内部基本都不捕获异常
    peteretep
        2
    peteretep  
       17 天前
    糙猛快的开发不需要考虑异常
    povsister
        3
    povsister  
       17 天前 via iPhone   ❤️ 53
    你这么严谨不适合写 python (狗头
    streamrx
        4
    streamrx  
       17 天前 via iPhone
    用 try
    wefgonujnopu
        5
    wefgonujnopu  
       17 天前
    python 动态类型确实不适合写大项目,异常的话,如果数据格式确保百分百不会问题,就不需要处理,如果是 IO 函数,处理文件 IO 或者网络 IO ,统一 try,一般出现错误的基本都是这些操作
    codersdp1
        6
    codersdp1  
       17 天前
    写奔放些
    iorilu
        7
    iorilu  
       17 天前   ❤️ 1
    你可以截获不同的具体异常阿

    try:

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

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

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


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

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

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

    如果希望严谨处理,你应该看 Rust 之类的有强错误标记的语言,或者等等接下来的 Kotlin 2.4 。
    pollux
        20
    pollux  
       17 天前   ❤️ 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  
       17 天前
    这就是经典的 error vs exception 争议
    Sawyerhou
        22
    Sawyerhou  
       17 天前
    go 的异常处理比较特殊,除非你不想学其他语言,否则走出舒适圈是不可避免的。
    Lockroach
        23
    Lockroach  
       17 天前   ❤️ 1
    fd, err: xxx
    if err != nil
    这样的行为,和 try: ... except Exception: ... 似乎也没什么区别,都是捕获一个笼统错误
    如果要捕获精确错误,应该有精细化的 Exception 实例
    iyaozhen
        24
    iyaozhen  
       17 天前
    大家不要纠结于楼主的 print 嘛 只是示例

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

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

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

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

    外围加一个大的 try...except 就行
    Rorysky
        33
    Rorysky  
       16 天前
    just let it fail
    coderluan
        34
    coderluan  
       16 天前
    except Exception as e:
    print(e)
    traceback.print_exc()
    arischow
        35
    arischow  
       16 天前
    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  
       16 天前
    只要 try 一次就行了, 异常类型可以判断, 也可用 traceback 解析, OP 这是没入门就来找茬
    DonaldVVV
        37
    DonaldVVV  
       16 天前
    try
    exception exception as e:
    print(f'{e!r}')

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

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

    except TypeRrror:
    ....
    except AtributeError:
    ...
    except ValueError:
    ....
    idealhs
        44
    idealhs  
       16 天前
    try catch 都不会写,你这是 go 和 python 的问题?很怀疑你是不是只会 go
    sky3hao9
        45
    sky3hao9  
       16 天前
    用惯了 GO, 说实话, 再看 Java, py, php 这些, 就跟看见屎粑粑一样
    yingxiangyu
        46
    yingxiangyu  
       16 天前
    logging.exception(e) 会把完整的调用栈都打印出来
    qiuhang
        47
    qiuhang  
       16 天前
    我看你不过是困在 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  
       16 天前
    同感,所以每次想到那帮提案把 try cache 加到 go 里的人是不是脑子有什么大病

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    对于你说的不知道有哪些异常的问题,先学会看文档吧,一开始就追代码容易追不对地方,基础库的文档还是比较全的,熟练了想再追代码的事。
    rockdodos
        71
    rockdodos  
       16 天前
    python EAFP ,外层 try 就完事了,我觉得 go 才罗里吧嗦的,一直 if err != nil
    xman99
        72
    xman99  
       16 天前
    php 可记录调用栈信息的,会有报错行数
    不知道 python 有没有对应处理方法
    DOLLOR
        73
    DOLLOR  
       16 天前   ❤️ 2
    自己封装一个嘛,反正 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  
       16 天前   ❤️ 2
    @qiuhang 异常可远不止这些,光是文件读取相关的异常就能列出一长串:

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

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

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

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

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

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

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

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

    当然,这些槽点不是这些语言生态特有的,是比较常见的开源库通用问题了...有些时候上生产,不乱用开源库是一个技术活,如何做好监控和故障重现都很需要好的开发者和 SRE 后面盯着。实话实说,这类问题一般在大家经常吐槽的 Java 和 Go 项目中处理起来稍微简单一些,一般这些的项目工程配置比较完善,即便出现定位也相对容易一些
    crackidz
        85
    crackidz  
       16 天前
    @crackidz 另外补充一下 OP 提到的一些具体问题,首先大概可以确定 OP 没读 Python 的官方文档。Python 的官方文档其实这方面做的比较好的典型,会明确对应的异常,比如你提到的 https://docs.python.org/3/library/json.html#json.load 当然,Python 其实历史项目比较久,有些文档属于上古时代的,所以不代表所有的都会有完善的记录和统一的格式
    nlimpid
        86
    nlimpid  
       16 天前
    我对 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  
       16 天前
    楼主只要把 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  
       16 天前
    如果你想捕获特定异常,那就写多个 except, 如果你只是单纯的想在出现异常的时候是哪个函数、哪一行报的错,那就在 except 里面 print(traceback.format_exc()), 这样会把整个异常出现的链路打印出来,具体到每一行
    Zy143L
        89
    Zy143L  
       16 天前   ❤️ 1
    ..这 处理几个常见的异常主动抛出就行了 其他没碰见的问题直接全局 try 兜底不就行了
    fbichijing
        90
    fbichijing  
       16 天前
    每一种语言有每一种语言的可取之处,它们射程不同,生态也不一样。
    如果你所熟悉的 go 语言通杀一切,你也不必学习 python 。
    如果说你刚才的目的是解析一个 json 文件,也就是原料就是文件,而目的就是将它解析成某种编程语言中的变量或者对象,方便操作。而这个过程,每种能处理这种操作的编程语言都有各自不同的表现形式。而“异常”或者“错误”,难道不是说法不同而已吗?它们都要面对:
    1. 文件不存在
    2. 文本编码不对
    3. 文件本身的格式有问题
    ...
    而这些需要共同面对的东西,你的 go 代码中,也只是将信息打印出来。(将有问题的信息打印出来你称之为健壮)。而每种能做这件事的编程语言,基本都有对应的捕捉这种信息的方式(行为),只是它们的代码表现有所差异而已。在我看来,捕捉这些信息是为了修复,而不是 go 语言捕捉的方式更优雅,更好看。这种事情一般有着先入为主的思想在里面,每个人的观念也有所不同。而太过于关注这个的话则忽略了主要目的,你只是想将文件正确解析出来。而输出的错误或者异常信息,它们也只是让你更好修复这些你意料之外的情况罢了。
    如果你想看到整个过程中可能出现的问题,你在外层一个 try except ,然后把堆栈信息打印出来不就好了?捕获特定异常的话,一般是为了程序能继续跑。而如果是意料之外的异常,多半还是用 traceback.print_exc() 这种方式更加合适,否则都没有足够的错误信息。
    ------
    我在学 go 中——基于某些原因——也没求一定要有什么结果。python >> go
    XWZCoffee
        91
    XWZCoffee  
       16 天前
    我就想问一下,你写 ts 难道不跟 py 一样吗,不一样都是 Error ,然后你需要定义自己的 Error ,比如 AError extends Error,然后判断抛出来的 error 是什么 error ,instanceof 判断。
    fox0001
        92
    fox0001  
       16 天前 via Android
    从 Java 过来就容易适应了🐶
    sardina
        93
    sardina  
       16 天前
    你写的 go 代码也没处理打开文件时的特定异常,在 py 里咋就介意了
    ZX576
        94
    ZX576  
       15 天前
    满篇的 try...except 不可取,最佳实践是

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


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

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

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

    大概是一种平衡?专心于能跑就行 vs 完备的处理全部的情况。
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4528 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 05:39 · PVG 13:39 · LAX 22:39 · JFK 01:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.