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
loliordie
V2EX  ›  Python

简洁优雅 pythonic 的代码风格和更容易阅读的代码风格你更倾向哪一种?

  •  
  •   loliordie · 2020-09-27 18:07:10 +08:00 · 3524 次点击
    这是一个创建于 1526 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这个起因非常神奇, 是我跟另一位 dalao 刷 LC 一道 EASY 题时产生的讨论.

    题目 LC. 234 的 O(1)空间复杂度解法, 由于是三刷我们的思路完全一致, 都是利用回文对称性寻找中间点的同时将前半部分指向关系翻转后进行比较, 但代码风格的不同却造成了别人阅读代码的不同反应.

    这是大佬的解答部分代码, 非常 pythonic, 可以看出使用了好几个骚操作来压缩代码.

    fast, slow, pre = head, head, None
    while fast and fast.next:
        fast = fast.next.next
        pre, slow.next, slow = slow, pre, slow.next
    slow = slow.next if fast else slow
    while slow and slow.val == pre.val:
        pre, slow = pre.next, slow.next
    return not pre
    

    这是我的烂代码

    fast = head
    slow = head
    pre = None
    
    while fast and fast.next:
        fast = fast.next.next
        temp = slow
        slow = slow.next
        temp.next = pre
        pre = temp
    
    if fast:
        slow = slow.next
    
    while slow and slow.val == pre.val:
        pre = pre.next
        slow = slow.next
    
    if not pre:
        return True
    else:
        return False
    

    核心逻辑完全一致, 但是在给一起刷题的一个大三实习生看时, 对方表示 dalao 的代码比较难懂, 反而觉得我的烂代码比较适合在工作中使用, 因为一眼就能看明白不会浪费时间.

    感觉有点迷茫在工作中应该使用什么样的代码风格了...

    30 条回复    2020-10-09 19:27:23 +08:00
    linw1995
        1
    linw1995  
       2020-09-27 19:09:20 +08:00
    对于这两段代码来说,肯定是更容易阅读的好。现在回答标题问题,两种风格并不冲突…
    chinazz
        2
    chinazz  
       2020-09-27 19:18:21 +08:00
    第一种可读性也不差吧。感觉第一种读起来会更快
    Hstar
        3
    Hstar  
       2020-09-27 19:18:45 +08:00
    多写写,写多了就变成第一种了
    Trim21
        4
    Trim21  
       2020-09-27 19:20:31 +08:00 via Android   ❤️ 3
    前三行和最后一行感觉大佬的写法好,其他的感觉你的写法好
    loliordie
        5
    loliordie  
    OP
       2020-09-27 19:26:35 +08:00
    @chinazz 实际上这个题目第四行, 由于指针移动的关系, 想根据赋值的优先级看清楚指针以及节点指向关系并不是很容易的事情, 需要先在脑内依次求出右侧三个值, 再依次赋值给三个变量. 这种做法虽然避免了中间变量, 但是增加了大脑的阅读负担...
    tcfenix
        6
    tcfenix  
       2020-09-27 19:33:56 +08:00
    代码上用骚操作提升性能或者降低空间复杂度这个的确听过,
    但是想问下,城里人都是觉得降低代码量能更牛逼么?代码量越低人越厉害么?还是代码跑的更快?

    lc 本身对性能有一定的需求,在满足的前提下代码就要让人容易看懂是最有帮助的

    前一种写法限定了只写 python 的人才习惯看
    后一种写法则是对 python 基础一般或者基本上只是熟悉其他语言的读者也友好

    可能写前者代码的大佬不需要把代码给其他普通人看吧....
    mcfog
        7
    mcfog  
       2020-09-27 19:48:38 +08:00   ❤️ 3
    第一种需要改进的:加空行

    第二种需要改进的:
    多赋值应该还是适当用的
    `if .. return True else return False` 这个谁这样写我头都给他打烂
    linnchord
        8
    linnchord  
       2020-09-27 19:50:59 +08:00
    对比一下,流程完全一样,纯粹是语法熟悉度问题。

    你 python 熟练了,语法翻译脑力消耗低于直白手打体力消耗以后自然就变成了上面的写法,没什么神秘的。
    reus
        9
    reus  
       2020-09-27 19:52:22 +08:00 via Android
    @loliordie 你应该右左右左右左地读,而不是右右右左左左
    imn1
        10
    imn1  
       2020-09-27 20:09:21 +08:00
    自己写喜欢第一种,读人家的希望第二种
    哈哈,我就俗人一个

    然后
    两个月后,自己写的也没记起当时的思路是什么 😛

    结束代码块的判断,我一般只写 if,不写 else,反正 False 的情况就执行下一句也是结束,没必要再写 else
    例如,continue/break/return/exit 这些
    如果 return 一定是 True/False 二选一,我也是第一种写法
    或者说,我会在满足需求的前提下,尽快 return 结束,甚至在循环里面就 return,而不是先 break 跳出去再 return
    dustinth
        11
    dustinth  
       2020-09-27 20:24:35 +08:00
    第一种代码不难懂. 唯一不好的地方是这一行:
    pre, slow.next, slow = slow, pre, slow.next
    因为这一行做了几件事情, 一行下来对读者心智负担比较重.
    aleung
        12
    aleung  
       2020-09-27 21:59:36 +08:00 via Android
    第一种写法好。唯一问题是没有加空行。
    littlewing
        13
    littlewing  
       2020-09-27 22:09:23 +08:00
    记住一点:代码是给人看的
    lsj8924
        14
    lsj8924  
       2020-09-27 23:03:11 +08:00
    第一种看起来多快呀,你一句分三行,眼球得多 paser 多少次。
    lithbitren
        15
    lithbitren  
       2020-09-27 23:06:55 +08:00   ❤️ 1
    个人愿意读第一种代码,只要效率没问题就行。

    用临时变量来实现交换对于 python 这种解释型语言来说是有效率差别的,直接元组交换视对象类型会快 20%-200%。

    如果不涉及交换,多行赋值会比单行赋值要快 20%-50%,单行赋值涉及到元组解构,如果没有交换的话应该是慢一点的,有交换的是解释器生成临时变量帮你交换,比自己声明的临时变量要快点。

    相同功能的 if 块运算以及 if-else 三元运算以及短路,从时间上几乎没有差别,怎么清晰怎么来,不过短路可以做多不止三元,多元运算的时候一般是短路比较快,但缺点就是一些布尔性质为 False 的变量不太好短路。

    利用变量的布尔性质来返回肯定比写 if 块要性能好点
    freakxx
        16
    freakxx  
       2020-09-27 23:21:34 +08:00
    标题是有倾向性的

    pythonic 的代码风格 和 非 pythonic 的代码风格 你更倾向哪一种?
    不容易阅读的代码风格和更容易阅读的代码风格 你更倾向哪一种?

    就 python 而言,这种赋值和解包是很舒服的,没必要用 tmp 来做一个转换


    至于 三元运算,这个比较短也是可以的,
    按第二种写法,如果要说的,补多个 else,补足情况也是好的做法

    最后的判断
    if True return True 这种“容易阅读”是完全没有必要的。
    freakxx
        17
    freakxx  
       2020-09-27 23:25:12 +08:00
    假如你从 python 角度看的话,

    第一种代码只要你肯给他加多几个空行那么是很漂亮的,
    而且用法是很简练的。
    nonduality
        18
    nonduality  
       2020-09-27 23:38:11 +08:00
    喜欢第一种,不爱罗嗦、低效的写法
    Rorysky
        19
    Rorysky  
       2020-09-27 23:42:19 +08:00
    没什么区别,编译器看来都是一样的
    inframe
        20
    inframe  
       2020-09-27 23:47:43 +08:00
    PEP 8:
    Guido 的一个重要的见解是,代码阅读的次数比编写的次数多。这里提供的指南旨在提高代码的可读性,并使各种不同的 Python 代码一致。如 PEP20 所说,“易读性非常重要”。

    https://www.python.org/dev/peps/pep-0008/
    cmdOptionKana
        21
    cmdOptionKana  
       2020-09-28 00:15:49 +08:00
    明显第一种更好,你不给人家加空行不厚道啊。
    lxilu
        22
    lxilu  
       2020-09-28 00:55:47 +08:00 via iPhone
    这倒看不出 pythonic……
    NoobX
        23
    NoobX  
       2020-09-28 02:26:35 +08:00
    原始代码并不属于故意缩短代码行数的类别,见过有代码为了炫技,在一行内用很多的 for 和 if-else 嵌套,个人不太推荐这么干,十分影响可读性。
    总体来说在不影响可读性的前提下,越精炼越好。相比之下,我认为你给出的原始代码更易读
    goinghugh
        24
    goinghugh  
       2020-09-28 08:31:28 +08:00
    我觉得第一种好,一眼就看出要做什么了; 换个问题,写 Java 时,用 stream 还是写 for-each 比较好写易读?
    InkStone
        25
    InkStone  
       2020-09-28 10:09:58 +08:00   ❤️ 1
    对于懂 Python 的人来说,第一种既更 pythonic,也更易读。

    另外赞同上面的看法,
    if not pre:
    return True
    else:
    return False
    这种写法不管在哪里都要被打死的
    cassyang
        26
    cassyang  
       2020-09-28 10:57:16 +08:00
    第一个哪里不好读了。。
    component
        27
    component  
       2020-09-28 11:02:16 +08:00
    @mcfog @InkStone 不懂就问,这样写有什么问题吗?是不是要用三元运算符来写?区别很大么?
    aguesuka
        28
    aguesuka  
       2020-09-28 12:44:11 +08:00 via Android
    @component return not pre 。你的 ide 没有警告吗?
    laike9m
        29
    laike9m  
       2020-10-02 17:37:56 +08:00 via Android
    第一个,因为它用的都是最常用的写法,没有任何花哨的地方。你觉得骚只是因为你不熟悉语法而已。
    cominghome
        30
    cominghome  
       2020-10-09 19:27:23 +08:00
    pythonic 骚东西很多,这一块我了解得不多,但是第一个例子里显然都是很实用的技巧,我投第一个
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2594 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 10:39 · PVG 18:39 · LAX 02:39 · JFK 05:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.