这个起因非常神奇, 是我跟另一位 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 的代码比较难懂, 反而觉得我的烂代码比较适合在工作中使用, 因为一眼就能看明白不会浪费时间.
感觉有点迷茫在工作中应该使用什么样的代码风格了...
![]() | 1 linw1995 2020-09-27 19:09:20 +08:00 对于这两段代码来说,肯定是更容易阅读的好。现在回答标题问题,两种风格并不冲突… |
![]() | 2 chinazz 2020-09-27 19:18:21 +08:00 第一种可读性也不差吧。感觉第一种读起来会更快 |
3 Hstar 2020-09-27 19:18:45 +08:00 多写写,写多了就变成第一种了 |
![]() | 4 Trim21 2020-09-27 19:20:31 +08:00 via Android ![]() 前三行和最后一行感觉大佬的写法好,其他的感觉你的写法好 |
5 loliordie OP @chinazz 实际上这个题目第四行, 由于指针移动的关系, 想根据赋值的优先级看清楚指针以及节点指向关系并不是很容易的事情, 需要先在脑内依次求出右侧三个值, 再依次赋值给三个变量. 这种做法虽然避免了中间变量, 但是增加了大脑的阅读负担... |
6 tcfenix 2020-09-27 19:33:56 +08:00 代码上用骚操作提升性能或者降低空间复杂度这个的确听过, 但是想问下,城里人都是觉得降低代码量能更牛逼么?代码量越低人越厉害么?还是代码跑的更快? lc 本身对性能有一定的需求,在满足的前提下代码就要让人容易看懂是最有帮助的 前一种写法限定了只写 python 的人才习惯看 后一种写法则是对 python 基础一般或者基本上只是熟悉其他语言的读者也友好 可能写前者代码的大佬不需要把代码给其他普通人看吧.... |
![]() | 7 mcfog 2020-09-27 19:48:38 +08:00 ![]() 第一种需要改进的:加空行 第二种需要改进的: 多赋值应该还是适当用的 `if .. return True else return False` 这个谁这样写我头都给他打烂 |
![]() | 8 linnchord 2020-09-27 19:50:59 +08:00 对比一下,流程完全一样,纯粹是语法熟悉度问题。 你 python 熟练了,语法翻译脑力消耗低于直白手打体力消耗以后自然就变成了上面的写法,没什么神秘的。 |
![]() | 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 |
![]() | 11 dustinth 2020-09-27 20:24:35 +08:00 第一种代码不难懂. 唯一不好的地方是这一行: pre, slow.next, slow = slow, pre, slow.next 因为这一行做了几件事情, 一行下来对读者心智负担比较重. |
![]() | 12 aleung 2020-09-27 21:59:36 +08:00 via Android 第一种写法好。唯一问题是没有加空行。 |
13 littlewing 2020-09-27 22:09:23 +08:00 记住一点:代码是给人看的 |
14 lsj8924 2020-09-27 23:03:11 +08:00 第一种看起来多快呀,你一句分三行,眼球得多 paser 多少次。 |
![]() | 15 lithbitren 2020-09-27 23:06:55 +08:00 ![]() 个人愿意读第一种代码,只要效率没问题就行。 用临时变量来实现交换对于 python 这种解释型语言来说是有效率差别的,直接元组交换视对象类型会快 20%-200%。 如果不涉及交换,多行赋值会比单行赋值要快 20%-50%,单行赋值涉及到元组解构,如果没有交换的话应该是慢一点的,有交换的是解释器生成临时变量帮你交换,比自己声明的临时变量要快点。 相同功能的 if 块运算以及 if-else 三元运算以及短路,从时间上几乎没有差别,怎么清晰怎么来,不过短路可以做多不止三元,多元运算的时候一般是短路比较快,但缺点就是一些布尔性质为 False 的变量不太好短路。 利用变量的布尔性质来返回肯定比写 if 块要性能好点 |
![]() | 16 metamask 2020-09-27 23:21:34 +08:00 标题是有倾向性的 pythonic 的代码风格 和 非 pythonic 的代码风格 你更倾向哪一种? 不容易阅读的代码风格和更容易阅读的代码风格 你更倾向哪一种? 就 python 而言,这种赋值和解包是很舒服的,没必要用 tmp 来做一个转换 至于 三元运算,这个比较短也是可以的, 按第二种写法,如果要说的,补多个 else,补足情况也是好的做法 最后的判断 if True return True 这种“容易阅读”是完全没有必要的。 |
![]() | 17 metamask 2020-09-27 23:25:12 +08:00 假如你从 python 角度看的话, 第一种代码只要你肯给他加多几个空行那么是很漂亮的, 而且用法是很简练的。 |
![]() | 18 nonduality 2020-09-27 23:38:11 +08:00 喜欢第一种,不爱罗嗦、低效的写法 |
![]() | 19 Rorysky 2020-09-27 23:42:19 +08:00 没什么区别,编译器看来都是一样的 |
![]() | 20 inframe 2020-09-27 23:47:43 +08:00 PEP 8: Guido 的一个重要的见解是,代码阅读的次数比编写的次数多。这里提供的指南旨在提高代码的可读性,并使各种不同的 Python 代码一致。如 PEP20 所说,“易读性非常重要”。 https://www.python.org/dev/peps/pep-0008/ |
![]() | 21 cmdOptionKana 2020-09-28 00:15:49 +08:00 明显第一种更好,你不给人家加空行不厚道啊。 |
22 lxilu 2020-09-28 00:55:47 +08:00 via iPhone 这倒看不出 pythonic…… |
23 NoobX 2020-09-28 02:26:35 +08:00 原始代码并不属于故意缩短代码行数的类别,见过有代码为了炫技,在一行内用很多的 for 和 if-else 嵌套,个人不太推荐这么干,十分影响可读性。 总体来说在不影响可读性的前提下,越精炼越好。相比之下,我认为你给出的原始代码更易读 |
24 goinghugh 2020-09-28 08:31:28 +08:00 我觉得第一种好,一眼就看出要做什么了; 换个问题,写 Java 时,用 stream 还是写 for-each 比较好写易读? |
![]() | 25 InkStone 2020-09-28 10:09:58 +08:00 ![]() 对于懂 Python 的人来说,第一种既更 pythonic,也更易读。 另外赞同上面的看法, if not pre: return True else: return False 这种写法不管在哪里都要被打死的 |
26 cassyang 2020-09-28 10:57:16 +08:00 第一个哪里不好读了。。 |
29 laike9m 2020-10-02 17:37:56 +08:00 via Android 第一个,因为它用的都是最常用的写法,没有任何花哨的地方。你觉得骚只是因为你不熟悉语法而已。 |
![]() | 30 cominghome 2020-10-09 19:27:23 +08:00 pythonic 骚东西很多,这一块我了解得不多,但是第一个例子里显然都是很实用的技巧,我投第一个 |