阅读 Python 代码的困难 - V2EX
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
shyrock
V2EX    Python

阅读 Python 代码的困难

  •  
  •   shyrock 2021-10-11 11:47:05 +08:00 3967 次点击
    这是一个创建于 1462 天前的主题,其中的信息可能已经有所发展或是发生改变。
    已经轻度使用 python 两年了,始终觉得阅读别人的 python 源码会有些困难。
    比如在一个函数中,很难找到传入参数的定义,导致难以精确理解本函数的功能。
    作为对比,以前用 c++,所有变量和参数都明确声明了类型,可以很精确地定位到该类型地定义。用于辅助理解当前函数的功能。

    是我没找到方法?还是这就是 python 的缺陷?
    18 条回复    2021-11-21 18:41:39 +08:00
    xmt328
        1
    xmt328  
       2021-10-11 14:05:17 +08:00
    我感觉这是弱类型语言的通病
    我也一直不习惯
    shyrock
        2
    shyrock  
    OP
       2021-10-11 14:15:21 +08:00
    @xmt328 #1 然而 python 是强类型的。。。
    AlexLokhart
        3
    AlexLokhart  
       2021-10-11 14:34:07 +08:00
    我觉得应该算“缺陷”吧,毕竟整体看起来就像是伪代码,如果别人有良好的代码习惯不算是问题,如果对方命名用 abc,ijk,那就很麻烦,python 3 虽然可以指定类型 def do_something( name : type ) -> return_type,不过不能期待别人也那么做了
    abersheeran
        4
    abersheeran  
       2021-10-11 14:39:49 +08:00
    是的,这正是动态类型语言的弱点。所以 Javascript 有了 TypeScript,Python 有了 Type hint 。

    Type hint 的例子 https://github.com/abersheeran/baize,几乎没有 Any,很接近静态类型语言了,读起来应该会比较简单。
    shyrock
        5
    shyrock  
    OP
       2021-10-11 15:00:18 +08:00
    @AlexLokhart #3 不知道 pycharm 一类的 IDE 有没有办法从代码中推断出类型。
    Dockerfile
        6
    Dockerfile  
       2021-10-11 21:06:00 +08:00
    @shyrock 没有的 解释器也是运行时才能知道吧,只能祈祷对方的 Type hint 比较完善。。
    princelai
        7
    princelai  
       2021-10-12 09:39:52 +08:00
    @shyrock #5 没办法推导,动态类型就这样,type hint 也是写给人看的,编译器会忽略

    ls = [1,"2","c"]
    for x in ls:
    pass

    x 的类型没法提前判断,即使提前声明,运行时也可以任意更改
    lppdao
        8
    lppdao  
       2021-10-12 10:13:56 +08:00
    @shyrock 我也有这样的困惑, 特别是复杂结构的参数, 没有文档根本不知道怎么搞, 以至于要看 c++的版本来确定类型.... 不知道你有没有找到什么好办法
    2i2Re2PLMaDnghL
        9
    2i2Re2PLMaDnghL  
       2021-10-12 11:05:30 +08:00
    @shyrock 只能从已知的开始推断,依赖于有 stub 的模块( builtin 和 std 应该都有 stub 了?)。好在,许多常用的模块新增了 stub (可能单独成包)推断能力也不强。
    julyclyde
        10
    julyclyde  
       2021-10-12 17:20:19 +08:00
    不过参数的定义即使没有类型也能看明白吧
    shyrock
        11
    shyrock  
    OP
       2021-10-12 18:16:20 +08:00
    @julyclyde #10 怎么做到的?
    rationa1cuzz
        12
    rationa1cuzz  
       2021-10-12 19:45:49 +08:00
    动态类型的通病,无解,不过 py3 都支持入参类型的注释,类似
    def demo(i:int,a) -> bool:错的话解释器都会有高亮
    featureoverload
        13
    featureoverload  
       2021-10-12 21:51:05 +08:00
    1. 虽然很高级的工程师(对程序理解很深)并不需要很多 type hints ;但 type hints 确实有是要比没有好得多的。

    2. Python 可以用很短的代码表达很多的内容(知识)。所以有些代码不具备相关知识自然是看不懂的。

    比如,没有掌握递归知识的初学者,看递归函数是很难理解的:

    def fib(n):
    ....if n < 0:
    ........raise ValueError("can't be negative")
    ....elif n <= 1:
    ........return n
    ....return fib(n-2) + fib(n-1)

    (递归不是“内容很多”的知识,所以其它语言也可以用很短的代码实现,这里是强调掌握不掌握这个知识对代码理解的帮助问题)

    比如如果没有了解数据结构的特点和一点训练,是很难看懂这段代码:

    def find_duplicates(list_):
    ....existed, duplicate = set(), set()
    ....for item in list_:
    ........if item in existed:
    ............duplicate.add(item)
    ........else:
    ............existed.add(item)
    ....return duplicate

    duplicates = find_duplicates(values)


    有些疯狂的孩子甚至可以去掉上面这个函数,"一行"得到结果(为了方便阅读,我把调用函数的参数换行):

    duplicates = reduce(
    ....lambda case, item: (case[item in case[False]].add(item), case)[-1],
    ....values,
    ,,,,{True: set(), False: set()}
    )[True]

    所以,要说不好读,确实很多情况都会不好读。
    这取决与每个人对软件的理解程度。
    jaredyam
        14
    jaredyam  
       2021-10-12 22:29:26 +08:00
    我的两点看法:
    1. 原作者代码具有较高可读性和包含适当或完备的 type hint 肯定是提升阅读体验,这也正是多数 Python 项目的「加分项」;
    2. Python 项目很多是算法驱动,很多时候对一些数理逻辑的理解更费时间,项目作者有时候也未必对代码本身精益求精;
    dayeye2006199
        15
    dayeye2006199  
       2021-10-13 01:22:32 +08:00
    多人协作需要 type hints 和 docstring,否则神仙难救。

    可以在 linting 阶段加入 mypy 或者 pyre 这样的类型检查器,让大家尽量不全类型信息。
    Mark24
        16
    Mark24  
       2021-10-14 16:24:06 +08:00
    个人观点:

    其实类型注解意义不大,加了反而对动态语言是个约束,丧失了动态语言的优势

    动态语言,需要配合单测。单测的意义跟类型是一样的,甚至比类型还牛一点。理论上单测应该起到各种类型输入的 例子的作用。

    但是现实中业务仔们没空写。
    shyrock
        17
    shyrock  
    OP
       2021-10-14 16:54:51 +08:00
    @Mark24 #16 不同意单测能替代类型提示。对于读代码的人来说,一段简单的代码因为类型不清楚而无法理解背后的意图,再去看单测也很难理解。这就导致代码的维护变得极为困难。

    现代代码,最重要的是让人容易读懂。
    shm7
        18
    shm7  
       2021-11-21 18:41:39 +08:00
    参数的定义,写得好的库,都有类似 pythondoc 的实现,怎么会不好读呢。我看到也就是一些底层实现非 Python 的才会有这类问题。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     826 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 21:31 PVG 05:31 LAX 14:31 JFK 17:31
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86