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

2020-09-27 18:07:10 +08:00
 loliordie

这个起因非常神奇, 是我跟另一位 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 的代码比较难懂, 反而觉得我的烂代码比较适合在工作中使用, 因为一眼就能看明白不会浪费时间.

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

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

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

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

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

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

你 python 熟练了,语法翻译脑力消耗低于直白手打体力消耗以后自然就变成了上面的写法,没什么神秘的。
reus
2020-09-27 19:52:22 +08:00
@loliordie 你应该右左右左右左地读,而不是右右右左左左
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
2020-09-27 20:24:35 +08:00
第一种代码不难懂. 唯一不好的地方是这一行:
pre, slow.next, slow = slow, pre, slow.next
因为这一行做了几件事情, 一行下来对读者心智负担比较重.
aleung
2020-09-27 21:59:36 +08:00
第一种写法好。唯一问题是没有加空行。
littlewing
2020-09-27 22:09:23 +08:00
记住一点:代码是给人看的
lsj8924
2020-09-27 23:03:11 +08:00
第一种看起来多快呀,你一句分三行,眼球得多 paser 多少次。
lithbitren
2020-09-27 23:06:55 +08:00
个人愿意读第一种代码,只要效率没问题就行。

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

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

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

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

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

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


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

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

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

https://www.python.org/dev/peps/pep-0008/

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

https://www.v2ex.com/t/711022

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

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

© 2021 V2EX