在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):shendeguize/GooglePythonStyleGuideCN开源软件地址(OpenSource Url):https://github.com/shendeguize/GooglePythonStyleGuideCN开源编程语言(OpenSource Language):开源软件介绍(OpenSource Introduction):谷歌Python代码风格指南 中文翻译Update: 2020.01.31 Translator: shendeguize@github Link: https://github.com/shendeguize/GooglePythonStyleGuideCN 本翻译囿于水平,可能有不准确的地方,欢迎指出,谢谢大家 如有引用,请注明出处 0 目录
1 背景Python是谷歌主要是用的动态语言,本风格指导列举了使用Python编程时应该做和不该做的事项(dos & don'ts) 为了帮助你正确地组织代码,我们编写了一个Vim的设置文件.对于Emacs,默认设置即可. 许多团队使用yapf自动格式工具来避免格式争议 2 Python语言规则2.1 Lint对代码使用 2.1.1Definition(以下都译为定义)
2.1.2 Pros能够发现一些易被遗漏的错误,类似拼写错误,调用早于声明等等. 2.1.3 Cons
a. Write around it(适配上下文风格) b. 压制一些警告 c. 优化工具 2.1.4 Decision(以下都译为建议)确保对代码应用 如果一些警告是不合适的,就抑制这些警告,这是为了让其他警告不会被隐藏.为了压制警告,可以设置行级别的注释: dict = 'something awful' # Bad Idea... pylint: disable=redefined-builtin
如果抑制警告的原因在标识名称中表述不够清晰,请额外添加注解. 用这种方式来抑制警告的优点是我们能够简单地找到抑制的警告并且重新访问这些警告. 可以通过下述方式来获得 pylint --list-msgs 用下述方式来获取某个特定消息的更多具体信息: pylint --help-msg=C6409 优先使用 def viking_cafe_order(spam, beans, eggs=None):
del beans, eggs # Unused by vikings.
return spam + spam + spa 其他可以用来抑制警告的方式包括用 2.2 Imports只在import包和模块的时候使用 2.2.1 定义一个模块到另一个模块之间共享代码的复用性机制 2.2.2 Pros命名空间管理约定简单,每个标识的源都一致性地被指明了.例如 2.2.3 Cons模块名可能会有冲突,一些模块名可能很长,比较不方便 2.2.4 建议
以 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:(假设文件在 # 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 不应该假设主代码所在路径被包含在 2.4 异常异常处理是允许使用的,但使用务必谨慎 2.4.1 定义异常是一种从正常代码段控制流中跳出以处理错误或者其他异常条件的手段. 2.4.2 Pros正常代码的控制流时不会被错误处理代码影响的.异常处理同样允许在某些情况下,控制流跳过多段代码,例如在某一步从N个嵌入函数返回结果而非强行延续错误代码. 2.4.3 Cons可能会让控制流变的难于理解,也比较容易错过调用库函数的报错. 2.4.4 建议异常必定遵循特定条件:
不要使用 Yes: def connect_to_next_port(self, minimum):
"""Connects to the next available port.
Args:
minimum: A port value greater or equal to 1024.
Returns:
The new minimum port.
Raises:
ConnectionError: If no available port is found.
"""
if minimum < 1024:
# Note that this raising of ValueError is not mentioned in the doc
# string's "Raises:" section because it is not appropriate to
# guarantee this specific behavioral reaction to API misuse.
# 注意抛出ValueError这件事是不在docstring中的Raises中提及, 因为这样并适合保障对于API误用的特殊反馈
raise ValueError('Minimum port must be at least 1024, not %d.' % (minimum,))
port = self._find_next_open_port(minimum)
if not port:
raise ConnectionError('Could not connect to service on %d or higher.' % (minimum,))
assert port >= minimum, 'Unexpected port %d when minimum was %d.' % (port, minimum)
return port No: def connect_to_next_port(self, minimum):
"""Connects to the next available port.
Args:
minimum: A port value greater or equal to 1024.
Returns:
The new minimum port.
"""
assert minimum >= 1024, 'Minimum port must be at least 1024.'
port = self._find_next_open_port(minimum)
assert port is not None
return port
try:
raise Error()
except Error as error:
pass 2.5 全局变量避免全局变量 2.5.1 定义在模块级别或者作为类属性声明的变量 2.5.2 Pros有些时候有用 2.5.3 Cons在import的过程中,有可能改变模块行为,因为在模块首次被引入的过程中,全局变量就已经被声明 2.5.4 建议避免全局变量 作为技术变量,模块级别的常量是允许并鼓励使用的.例如 如果需要,全局变量需要在模块级别声明,并且通过在变量名前加 2.6 内嵌/局部/内部 类和函数内嵌局部函数或类在关闭局部变量时是可以的.内部类意识可用的.(译注:这里我的理解是当内嵌局部函数或类是和局部变量在同一个封闭作用域内是可以的.) 2.6.1 定义类可以在方法,函数,类内定义.函数可以在方法或函数内定义.内嵌函数对封闭作用域的变量具有只读访问权限. 2.6.2 Pros允许定义只在非常有限作用域内可用的工具类或工具函数.Very ADT-y(??符合抽象数据类型要求???),通常用于实现装饰器 2.6.3 Cons内嵌或局部类的实例是不能被pickle的,内嵌函数或类是不能被直接测试的.嵌套会让外部函数更长并且更难读懂. 2.6.4 建议除了一些特别声明,这些内嵌/局部/内部类和函数都是可以的.
避免内嵌函数或类除了需要关闭一个局部值的时候.(译者理解可能是除了将局部变量封闭在同一个作用域的情况以外).不要把一个函数转为内嵌指示为了避免访问.在这种情况下,把函数置于模块级别并在函数名前加 2.7 列表推导和生成器表达式在简单情况下是可用的 2.7.1 定义List, Dict和Set推导生成式以及生成器表达式提供了一个简明有效的方式来生成容器和迭代器而不需要传统的循环, 2.7.2 Pros简单地推导表达比其他的字典,列表或集合生成方法更加简明清晰.生成器表达式可以很有效率,因为完全避免了生成列表. 2.7.3 Cons负载的推导表达式或生成器表达式很难读懂 2.7.4 建议简单情况下使用时可以的.每个部分(mapping表达式,filter表达式等)都应该在一行内完成.多个for条款或者filter表达式是不允许的.当情况变得很复杂的适合就使用循环. Yes: result = [mapping_expr for value in iterable if filter_expr]
result = [{'key': value} for value in iterable
if a_long_filter_expression(value)]
result = [complicated_transform(x)
for x in iterable if predicate(x)]
descriptive_name = [
transform({'key': key, 'value': value}, color='black')
for key, value in generate_iterable(some_input)
if complicated_condition_is_met(key, value)
]
result = []
for x in range(10):
for y in range(5):
if x * y > 10:
result.append((x, y))
return {x: complicated_transform(x)
for x in long_generator_function(parameter)
if x is not None}
squares_generator = (x**2 for x in range(10))
unique_names = {user.name for user in users if user is not None}
eat(jelly_bean for jelly_bean in jelly_beans
if jelly_bean.color == 'black') No: result = [complicated_transform(
x, some_argument=x+1)
for x in iterable if predicate(x)]
result = [(x, y) for x in range(10) for y in range(5) if x * y > 10]
return ((x, y, z)
for x in range(5)
for y in range(5)
if x != y
for z in range(5)
if y != z) |