Python Style Rules

Line length:
每行的最大长度为80字符,下面特殊情况除外:

  • 长 的import声明
  • URLs, pathnames, or long flags in comments.
  • 因包含空格而不便划分的URLs, pathnames
  • Pylint disable comments. (e.g.: # pylint: disable=invalid-name)

如果必要的话在表达式中增加括号进行换行。

Yes: foo_bar(self, width, height, color='black', design=None, x='foo',
             emphasis=None, highlight=0)

     if (width == 0 and height == 0 and
         color == 'red' and emphasis == 'strong'):
    x = ('This will build a very long long '
     'long long long long long long string')

URL路径

Yes:  # See details at
      # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_name_extension_full_specification.html
No:  # See details at
     # http://www.example.com/us/developer/documentation/api/content/\
     # v2.0/csv_file_name_extension_full_specification.html

with表达式超过三行或多行时可以用分号换行,当表达式为两行时,可以换成两个with表达式。

Yes:  with very_long_first_expression_function() as spam, \
          very_long_second_expression_function() as beans, \
          third_thing() as eggs:
         place_order(eggs, beans, spam, beans)
No:  with VeryLongFirstExpressionFunction() as spam, \
         VeryLongSecondExpressionFunction() as beans:
      PlaceOrder(eggs, beans, spam, beans)
Yes:  with very_long_first_expression_function() as spam:
         with very_long_second_expression_function() as beans:
             place_order(beans, spam)

Parentheses:
可以在元组周围使用括号。不要在返回语句或条件语句中使用它们,除非使用括号来表示隐含的行继续符或表示元组。

No:  if (x):
         bar()
     if not(x):
         bar()
     return (foo)

用4个空格缩进代码块。 切勿使用制表符或混合制表符和空格。在隐含行继续的情况下,您应该根据行长度部分的示例,垂直对齐被包装的元素;或者使用4个空格的悬挂缩进,在这种情况下,在第一行的左括号或括号之后不应该有任何内容。

Yes:   # Aligned with opening delimiter
       foo = long_function_name(var_one, var_two,
                                var_three, var_four)
       meal = (spam,
               beans)

       # Aligned with opening delimiter in a dictionary
       foo = {
           long_dictionary_key: value1 +
                                value2,
           ...
       }

       # 4-space hanging indent; nothing on first line
       foo = long_function_name(
           var_one, var_two, var_three,
           var_four)
       meal = (
           spam,
           beans)

       # 4-space hanging indent in a dictionary
       foo = {
           long_dictionary_key:
               long_dictionary_value,
           ...
       }
No:    # Stuff on first line forbidden
      foo = long_function_name(var_one, var_two,
          var_three, var_four)
      meal = (spam,
          beans)

      # 2-space hanging indent forbidden
      foo = long_function_name(
        var_one, var_two, var_three,
        var_four)

      # No hanging indent in a dictionary
      foo = {
          long_dictionary_key:
          long_dictionary_value,
          ...
      }

Trailing commas in sequences of items?:
在容器类型的) ] } 与最后一个元素不在同一行时,最后一个元素后面加逗号。

Yes:   golomb3 = [0, 1, 3]
Yes:   golomb4 = [
          0,
          1,
          4,
          6,
      ]
No:    golomb4 = [
          0,
          1,
          4,
          6
      ]

Blank Lines:
两个空白行: 函数与函数 函数与类 或者函数与类之间。
一个空白行:类中方法之间或者class与第一个方法之间。
def 下面没有空白行
函数或方法之间设置你认为合适的空白行。
Whitespace:
各种括号之间没有空白。

Yes: spam(ham[1], {eggs: 2}, [])
No:  spam( ham[ 1 ], { eggs: 2 }, [ ] )

逗号、分号、,冒号之前不要使用空格, 除了在每行的结尾其之后要用空格。

Yes: if x == 4:
         print(x, y)
     x, y = y, x
 No:  if x == 4 :
         print(x , y)
     x , y = y , x

列表、函数名、切片等与括号之间不要用空格。

Yes: spam(1)
No:  spam (1)
Yes: dict['key'] = list[index]
No:  dict ['key'] = list [index]

==, <, >, !=, <>, <=, >=, in, not in, is, is not, and, or, not, = 等加入空格, +, -, *, /, //, %, **, @ 加空格与否自己做判断。
Comments and Docstrings:
确保对模块、函数、方法docstrings和内联注释使用正确的样式。
docstring是一个字符串,它是包、模块、类或函数中的第一个语句。docstrings的三个双引号格式, 应组织为摘要行(一个物理行),以句点、问号或感叹号结尾,后跟一个空行,然后是docstring的其余部分,从第一行的第一个引号的相同光标位置开始。
函数与方法中:
一个函数必须有docstrings, 除非满足:

  • not externally visible
  • very short
  • obvious

docstrings 应该用描述性语言"""Fetches rows from a Bigtable.""", 不应该用强制性语言"""Fetch rows from a Bigtable.""" 功能的某些方面应记录在下面列出的特殊部分中。每个部分以标题行开始,以冒号结束。节应缩进两个空格,但标题除外。
Args: 按名称列出每个参数。描述应该跟在名称后面,并用冒号和空格分隔。如果描述太长而不能放在一个80个字符的行上,请使用2或4个空格的悬挂缩进(与文件的其余部分一致)
Returns: (or Yields: for generators) : 描述返回值的类型和语义。如果函数只返回none,则不需要此节。如果docstring以returns或yield开头(例如,"""Returns row from Bigtable as a tuple of strings."""),并且句首足以描述返回值,则也可以省略。
Raises: 列出所有异常。

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
    """Fetches rows from a Bigtable.

    Retrieves rows pertaining to the given keys from the Table instance
    represented by big_table.  Silly things may happen if
    other_silly_variable is not None.

    Args:
        big_table: An open Bigtable Table instance.
        keys: A sequence of strings representing the key of each table row
            to fetch.
        other_silly_variable: Another optional variable, that has a much
            longer name than the other args, and which does nothing.

    Returns:
        A dict mapping keys to the corresponding table row data
        fetched. Each row is represented as a tuple of strings. For
        example:

        {'Serak': ('Rigel VII', 'Preparer'),
         'Zim': ('Irk', 'Invader'),
         'Lrrr': ('Omicron Persei 8', 'Emperor')}

        If a key from the keys argument is missing from the dictionary,
        then that row was not found in the table.

    Raises:
        IOError: An error occurred accessing the bigtable.Table object.
    """

类中:

类应该在描述类的类定义下面有一个docstring。如果您的类具有公共属性,那么它们应该记录在这里的属性部分中,并遵循与函数的args部分相同的格式。

class SampleClass(object):
    """Summary of class here.

    Longer class information....
    Longer class information....

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Inits SampleClass with blah."""
        self.likes_spam = likes_spam
        self.eggs = 0

    def public_method(self):
        """Performs operation blah."""

块和内联注释:
最后一个需要注释的地方是代码中复杂的部分。如果你要在下一次代码审查时解释它,你现在应该对它进行评论。复杂的操作在操作开始前得到几行注释。注释与代码之间要有两个空白行。

# We use a weighted dictionary search to find out where i is in
# the array.  We extrapolate position based on the largest num
# in the array and the array size and then do binary search to
# get the exact number.

if i & (i-1) == 0:  # True if i is 0 or a power of 2.

Classes:
类中要明显表明继承的对象, Object对象不能省略。

Yes: class SampleClass(object):
         pass


     class OuterClass(object):

         class InnerClass(object):
             pass


     class ChildClass(ParentClass):
         """Explicitly inherits from another class already."""
No: class SampleClass:
        pass


    class OuterClass:

        class InnerClass:
            pass

Strings:
即使参数都是字符串,也可以使用格式化方法或%运算符来格式化字符串。不过,请用您的最佳判断在+和%(或格式)之间做出决定。

Yes: x = a + b
     x = '%s, %s!' % (imperative, expletive)
     x = '{}, {}'.format(first, second)
     x = 'name: %s; score: %d' % (name, n)
     x = 'name: {}; score: {}'.format(name, n)
     x = f'name: {name}; score: {n}'  # Python 3.6+
No: x = '%s%s' % (a, b)  # use + in this case
    x = '{}{}'.format(a, b)  # use + in this case
    x = first + ', ' + second
    x = 'name: ' + name + '; score: ' + str(n)

其中:f前缀可以简单有效的格式化字符串,比起format()方法具备更好的可读性

>>> name = 'Fred'
>>> age = 42
>>> f'He said his name is {name} and he is {age} years old.'
He said his name is Fred and he is 42 years old.

避免使用++=运算符在循环中累积字符串。因为字符串是不可变的,所以这会创建不必要的临时对象,并产生二次而不是线性运行时间。相反,将每个子字符串添加到一个列表中,并在循环终止后使用`’’.join。

Yes: items = ['<table>']
     for last_name, first_name in employee_list:
         items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name))
     items.append('</table>')
     employee_table = ''.join(items)
No: employee_table = '<table>'
    for last_name, first_name in employee_list:
        employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name)
    employee_table += '</table>'

同一个文件中‘’ “” 字符使用要一致, 可以在字符串中使用另一个引号字符,以避免在字符串中\转义

Yes:
  Python('Why are you hiding your eyes?')
  Gollum("I'm scared of lint errors.")
  Narrator('"Good!" thought a happy Python reviewer.')
No:
  Python("Why are you hiding your eyes?")
  Gollum('The lint. It burns. It burns us.')
  Gollum("Always the great lint. Watching. Watching.")

多行字符串首选""",而不是'''。项目可以选择将'''用于所有非docstring多行字符串,前提是它们也将'用于常规字符串。不管怎样,docStrings必须使用"""。注意,使用隐式行连接通常更为简单,因为多行字符串不会随着程序其余部分的缩进而流动.

Yes:
  print("This is much nicer.\n"
        "Do it this way.\n")
  No:
    print("""This is pretty ugly.
Don't do this.
""")

Files and Sockets:
使用with声明管理文件对象。

with open("hello.txt") as hello_file:
    for line in hello_file:
        print(line)

对于不支持with声明的file-like对象,使用contextlib.closing()

import contextlib

with contextlib.closing(urllib.urlopen("http://www.python.org/")) as front_page:
    for line in front_page:
        print(line)

** Imports formatting:**
Imports 应该独立成行。

Yes: import os
     import sys
No:  import os, sys

导入总是放在文件的顶部,在任何模块注释和docstring之后,以及模块全局和常量之前。导入应按最一般到次一般的顺序分组:

  • python标准库, 如import sys
  • 第三方模块或包, 如import tensorflow as tf
  • 代码库中子包导入, 如from otherproject.ai import mind

在每个分组中,导入应该按照字典顺序排序,忽略大小写,根据每个模块的完整包路径。

import collections
import queue
import sys

from absl import app
from absl import flags
import bs4
import cryptography
import tensorflow as tf

from book.genres import scifi
from myproject.backend.hgwells import time_machine
from myproject.backend.state_machine import main_loop
from otherproject.ai import body
from otherproject.ai import mind
from otherproject.ai import soul

Naming:
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_CONSTANT_NAME, global_var_name, instance_var_name, function_parameter_name, local_var_name

函数名、变量名和文件名应该是描述性的;不要使用缩写。尤其是,不要使用对项目之外的读者不明确或不熟悉的缩写,也不要通过删除单词中的字母来缩写。
Names to Avoid:

  • 单字符名称,只有在计数器或迭代器中使用。可以在try/except语句中使用“e”作为异常标识符。
  • 在包或模块中不要使用-
  • 类似__double_leading_and_trailing_underscore__

Naming Convention:

  • "Internal"意味着模块内部或者类中保护或私有
  • 预处理单个下划线_支持保护模块变量和函数(不包括在模块导入*中)。不支持__设置类中私有变量,因为它会影响可读性和可测试性,并且不是真正私有的(python中会把每个私有变量前加_类名)。
  • 用大写字母表示类名,用小写字母表示模块名。尽管有一些名为capwords.py的旧模块,但现在不鼓励这样做,因为当模块碰巧以类命名时,会让人感到困惑。(“wait——我写了import stringio还是从stringio import stringio?”)

File Naming:
python文件名必须具有.py扩展名,并且不能包含破折号-

Guidelines derived from Guido’s Recommendations:

python 每行数的增长趋势_缩进