Python 代码规范小结
本文主要是和大家分享python开发中常见的一些代码规范,希望对python新人码代码有所帮助吧。
law
一: 一切都与复杂度有关
二: 代码应当易于理解
对人:
"好程序员”应当竭尽全力, 把程序写得让其他程序员(以及以后的自己)容易理解.
对代码:
1. 代码被阅读的次数远多于编写和修改的次数
2. E = mc2 (Error = more codes)
对项目:
公式: 可行性=(当前价值+未来价值)/(实现成本+维护成本). 即相比降低实现成本, 降低维护成本更加重要
基础: 风格
团队成员遵守统一的风格, 保持风格的一致性, 减少理解难度
遵循基础的编码风格:
请仔细阅读, 使用对应编辑器插件工具协助检查
.
遵循 pep8 风格
.
利用pep8工具(编辑器相关插件)来解决这个问题, 在review之前处理. 以避免在review过程中出现此类问题.
.
.
遵循 Google Code Style / 中文版
.
.
不要吝啬空行, 把相关的代码行分组, 形成代码块. 声明按块组织起来, 并且把代码分成”段落”(按步骤/顺序/逻辑结构分), 排版合理
.
. 每行只写一个语句, 每行只声明一个变量
注释
注释应该有很高的 价值 (传递信息/空间占用)
. 代码本身应该尽力做到自说明
. 注释, 记录了在写代码过程中的思考, 保持紧凑, 简单准确的描述
.
不要使用尾注释. 容易被整行拷贝/不容易被编辑修改/逐渐腐烂
.
x = 1 # bad comment
# good commentx = 1
.
.
不需要的代码, 维护到版本库后(写明 commit info ), 然后删除. 不要注释起来
.
. 不要给不好的命名加注释, 应该去修改命名
. 不要给那些从代码本身就能 快速 推断出来的事实写注释.(不要为了注释而注释)
. 对于复杂的计算逻辑, 要给出注释, 可以通过列举例子, 简单的输入输出来描述
. 对于大段的逻辑或模块, 需要给总结性注释
. 注释代码时, 应注重-为何做, 而不是-怎么做
. 每行注释前用一个空行分开. 注释缩进要和相应代码一致
命名
把信息装入名字中.(自说明)
. 尽量短, 但是要包含足够的信息(刨掉其中毫无意义的词)
. 命名一定要有意义, 尽量少使用单个字符作为命名, 除非短表达式(列表解析/lambda等)以及小的作用域范围
. 常量大写, 变量小写, 类名驼峰, 函数名小写加下划线, 不要混用下划线和驼峰.
. 不要使用关键字命名, 例如 type 和 dir
. 避免使用容易混淆的命名, 防歧义
. 慎用首字母缩略词和缩写, 除非团队成员都理解(不要妄图用注释来解决这个问题, 即, 不要注释不好的命名)
. 不要使用大小写来区分不同对象
. 同一个变量, 在多个地方, 前后端/数据库/不同函数/请求等, 尽量保持命名一致性
. 不要害怕过长的命名, 保证易于理解和阅读(现代编辑器可以搞定自动补全和批量变更的问题)
. 使用具体的名字, 而不是泛化的名字, 例如 params/args 等, 没有隐含任何信息
. bool 类型, 除非名字本身有 True/False 的含义, 否则建议统一使用 is_ 前缀
. 不要使用双重否定的命名: is_not_pass
. for a in b , 注意 a 和 b 的单复数区分
常量
. 常量大写
. 作用于同一个模块/逻辑的多个常量, 建议使用统一的前缀
. 将常量统一组织到某个文件/某几个文件, 并写明注释.
. 函数/循环中的正则, 请预先 compile , 放入变量中.
. 善用 Enum , 对可读性提升很大
. 同一个枚举变量中, 其包含类型应当一致
变量
. 减少变量: 变量越多, 越难全部追踪其动向. a.减少没有价值的中间变量 b.减少中间结果(可以通过 提前返回 来消除) c.减少控制流变量
. 缩小变量作用域: 避免全局变量(命名空间污染). 需要做到让你的变量对尽量少的代码行可见.
. 变量定义尽量靠近其使用的地方, 或者, 在使用时定义.
. 不要使用 import * , 会出现各种 突如其来 的变量名, 可能导致名字空间污染, 造成诡异问题
数据结构
. dict , 不要使用 for key in d.keys() , 直接使用 for key in d
表达式
原则: 保持简短, 易懂.(拆分超长表达式)
. 抽取反复出现的长表达式到变量或者函数调用
. 使用解释变量, 将超长表达式中的自表达式抽取城一个解释变量.(抽取, 然后使用变量, 而不是每次都重复表达式)
. 总结变量: 一个表达式不需要解释, 但是装入一个新的变量中仍然有用. 短名字替代一大块代码. 例如: numbers[0]['obj'].name
. 使用摩根定理: not a and not b to not (a or b)
. 删除公共子表达式:如果发现某个表达式老是在你面前出现,就把它赋值给一个变量
. 中文, 请统一使用 u"中文"
. 表达式中避免使用 魔数 , 使用常量/枚举替代之
控制流: 分支
. if/else 顺序: a. 先处理正逻辑而不是负逻辑. b. 先处理掉简单的情况, 还能保证if/else在同一个屏幕内都可见(否则到了 else 需要回头查) c.先处理有趣或可疑的逻辑
. return early , 从函数中提前返回. 使用 guard clause 来实现. 某些情况返回后, 将不必要思考某个分支出口, 剩余注意力集中在为数不多的情况. 另一个好处是, 能有效减少代码缩进.
. 减少嵌套: 嵌套很深的代码很难理解, 每个嵌套层次会在读者’思维栈’上又增加了一个条件. 使用 return early 来减少嵌套. 而循环中的减少嵌套方式, 可以使用 if condition: continue/break 来进行 提早返回 .
. 减少嵌套: 当你对代码进行改动的时候, 从全新的角度审视它, 把它作为一个整体来看待.只关心局部, 不敢动旧有代码, 很容易一层层逻辑嵌套往里加导致深层嵌套
. 使用 is 来判定是否是 None , 而不是 ==
. 条件语句中参数顺序: 左侧变量, 右侧字面值/常量
. 默认情况都使用 if...else , 三目运算只有在最简单的情况下才使用
. if condition: return 则不需要 else
. 注意 if/else 的多层嵌套, 在某些情况下, 判断条件中恒真/恒假的情况
控制流: 循环
. 善用 enumerate 而不是维护 index 变量( enumerate 还可以从1开始计数)
. 除非必要(逻辑确实如此且带 break ), 否则不要使用 for...else .(增加理解成本)
. 不要使用 for _ in l: _.x , 可读性太差
. 减少循环内的 if...else... 嵌套层次, 可以使用 if condition: continue
控制流: 异常处理
异常日志同注释, 应该有很高的 价值 (传递信息/空间占用)
. 不要把所有代码放到 try except 中, 只捕获会出异常的代码片段. 注意粒度, 不要放入不必要的代码
. 不要吞掉异常, 处理或抛出, 同时要打日志(使用 logging 而不是 print 打日志)
. 谨慎使用 except Exception 捕获所有异常.
. 不要在 finally 语句中使用return进行返回, 有坑.
. 异常的错误信息要 有用 , 即足够明确, 对问题排查有帮助.
. 不要使用异常控制程序的流程. 滥用异常, 异常不应该处理正常逻辑
. 不要滥用异常, 底层被调用函数早已 try...except 处理了, 调用方不需要再次处理
函数
函数不要太大, 嵌套不要太深
. 参数命名的一致性: 多个参数, 选择一个有意义的顺序, 并始终一致地使用它(可读性更好, 更容易发现问题)
. 不要使用可变对象作为函数默认参数的值
. 一次只做一件事 , 注意函数大小, 注意抽象/拆分
. 抽取不相关的子问题到独立的函数中, 例如纯工具代码, 通用代码, 项目专属代码
. 抽取反复出现重复的代码到独立函数中
. return 值不要使用 0/1 来代表 True/False
. 同一个函数可能存在多个 return , 返回值要保持一致(个数/类型)
. return early , 减少阅读代码时的逻辑堆积, 减少贯穿函数始终用于最终判断return的变量数量. 超过3个就变得有些难以维护了, 阅读过程中确定其值有困难
. 如果函数调用链中, 参数或者return的值反复出现pack/unpack, 可以考虑用 dict 封装来进行传递.
. 如果发现每次调用一个函数后, 还需要对返回值进行二次处理, 则是函数封装得不够导致的. 需重构函数, 将处理加进去. (防止某次调用忘了二次处理导致的bug)
类
. 不要使用type进行类型检查, 用 isinstance
. 使用新式类, 驼峰命名
. 假设类的某个属性, 每次取出来都需要进行处理(格式化, 转换等, 例如日期格式), 使用 property 封装这层处理, 同时处理异常情况.
模块
. import 顺序: 标准库/第三方库/本项目, 之间使用空行隔开
. 多行 import , 请使用 from a import (b, c, d) 而不是 \\ 来进行换行
. 不要使用 from A import *
. 当相对独立的多个逻辑代码混杂放在一起, 或者发现constant文件超大包含了大量不同逻辑的产量, 可以考虑模块切分
抽象
. 一定不要机械地复制粘贴代码(会出现大量的重复代码), 应该从全局考虑是否可以抽象
. 多个函数之间, 如果仅有一两行代码不同, 则可以进行抽象提取
. 当一段相似的代码出现两次以上, 需要考虑封装(注意粒度)
设计
软件设计三大误区: 1.编写不必要的代码 2.代码难以修改 3.过分追求通用
. 思考足够充分, 减少过度设计
其他
. 熟悉标准库, 减少土制轮子的概率, 可以少写代码
. 熟悉框架/优秀第三方库提供的接口及特性, 原因同上
. 项目发布前, 移除所有 print 语句
. 文件/函数是否写明作者信息? 不, 版本记录中有作者信息. 容易形成 领地 , 他人不敢修改/不敢大改, 容易造成代码腐烂. 占用空间且没啥用.
文章来源:wklken's blog