这是一位朋友翻译的Google Python代码风格指南,很全面。可以作为公司的code review 标准,也可以作为自己编写代码的风格指南。希望对你有帮助。
Translator: shendeguize@github
Link: https://github.com/shendeguize/GooglePythonStyleGuideCN
本翻译囿于水平,可能有不准确的地方,欢迎指出,谢谢大家
1、背景
Python是谷歌主要使用的动态语言,本风格指导列举了使用Python编程时应该做和不该做的事项(dos & don'ts)
为了帮助你正确地组织代码,我们编写了一个Vim的设置文件.对于Emacs,默认设置即可.
许多团队使用yapf自动格式工具来避免格式争议
2、Python语言规则
2.1 Lint
对代码使用pylint
2.1.1Definition(以下都译为定义)
pylint是一个用于在Python代码中发现bug和代码风格问题的工具,,pylint查找那些常在非动态语言(例如C或C++)编译器中捕获的问题.由于Python是动态语言,一些警告可能不正确,不过应该非常少有错误警告.
2.1.2 Pros
能够发现一些易被遗漏的错误,类似拼写错误,调用早于声明等等.
2.1.3 Cons
pylint并不完美,为了更好的利用工具,我们有时候需要
a. Write around it(适配上下文风格)
b. 压制一些警告
c. 优化工具
2.1.4 Decision(以下都译为建议)
确保对代码应用pylint
如果一些警告是不合适的,就抑制这些警告,这是为了让其他警告不会被隐藏.为了压制警告,可以设置行级别的注释:
- dict = 'something awful' # Bad Idea… pylint: disable=redefined-builtin
pylint警告包含标识名(empty-docstring),谷歌专有的警告以g-开头.
如果抑制警告的原因在标识名称中表述不够清晰,请额外添加注解.
用这种方式来抑制警告的优点是我们能够简单地找到抑制的警告并且重新访问这些警告.
可以通过下述方式来获得pylint警告列表:
- pylint –list-msgs
用下述方式来获取某个特定消息的更多具体信息:
- pylint –help-msg=C6409
优先使用pylint: disable而非旧方法(pylint: disable-msg)如果要抑制由于参数未使用的警告,可以在函数开头del,并注释为什么要删除这些未使用参数,仅仅一句"unused"是不够的:
- def viking_cafe_order(spam, beans, eggs=None):
- del beans, eggs # Unused by vikings.
- return spam + spam + spa
其他可以用来抑制警告的方式包括用'_'作为未使用参数的标识,在参数名前增加'unused_',或者分配这些参数到'_'.这些方式是可以的,但是已经不鼓励继续使用.前两种方式会影响到通过参数名传参的调用方式,而最后一种并不能保证参数确实未被使用.
2.2 Imports
只在import包和模块的时候使用import,而不要应用在单独的类或函数.(这一条对于typing_module有特别的意外)
2.2.1 定义
一个模块到另一个模块之间共享代码的复用性机制
2.2.2 Pros
命名空间管理约定简单,每个标识的源都一致性地被指明了.例如x.Obj表示Obj是在模块x中定义的
2.2.3 Cons
模块名可能会有冲突,一些模块名可能很长,比较不方便
2.2.4 建议
- import x(当x是包或模块)
- from x import y (当x是包前缀,y是不带前缀的模块名)
- from x import y as z (当有重复模块名y或y过长不利于引用的时候)
- import y as z (仅在非常通用的简写的时候使用例如import numpy as np)
以sound.effects.echo为例:
- from sound.effects import echo…echo.EchoFilter(input, output, delay=0.7, atten=4)
不要使用相对引用,即便在同一包内,也使用完整包名import,这有助于避免无意重复import包.
从typing module和six.moves module import不适用上述规则
2.3 包
每一模块都要从完整路径import
2.3.1 Pros
能够避免模块名冲突以及由于模块搜索路径与作者预期不符而造成的错误引用.让查找模块更简单.
2.3.2 Cons
让部署代码时有些困难,因为包架构也需要赋值,不过对于现在的部署机制而言,这其实不是问题.
2.3.3 建议
所有的新代码都要从完整包名来import模块
import示例应该像这样:
Yes:
- # Reference absl.flags in code with the complete name (verbose).
- # 在代码中使用完整路径调用absl.flags
- import absl.flagsfrom doctor.who import jodie
- FLAGS = absl.flags.FLAGS
- # Reference flags in code with just the module name (common).
- # 在代码中只用包名来调用flags
- from absl import flagsfrom doctor.who import jodie
- FLAGS = flags.FLAGS
No:(假设文件在doctor/who中,jodie.py也在这里)
- # Unclear what module the author wanted and what will be imported. The actual
- # import behavior depends on external factors controlling sys.path.
- # Which possible jodie module did the author intend to import?
- # 不清楚作者想要哪个包以及最终import的是哪个包,
- # 实际的import操作依赖于受到外部参数控制的sys.path
- # 那么哪一个可能的jodie模块是作者希望import的呢?
- import jodie
不应该假设主代码所在路径被包含在sys.path中,即使有些时候可以work.在上一例代码中,我们应该认为import jodie指的是import一个叫做jodie的第三方包或者顶级目录中的jodie,而非一个当前路径的jodie.py