Python 编程规范

本文提供的 Python 编码规范基于 Python 主要发行版本的标准库。Python 编码规范的指导原则主要用于提升代码的可读性,使得在大量的 Python 代码中保持一致。许多项目有自己的编码规范,在出现规范冲突时,项目自身的规范优先。

Python 编码规范最常使用的是 PEP8 编码规范。

PEP8 编码规范中文版 PDF 下载地址:https://pan.baidu.com/s/1ZhrIODN1h1ccdXcPHbuDVQ

百度网盘提取码:o8oe

 

1. 命名

  • 文件名
  • 全部小写,可使用下划线。

  • 使用简短的小写的名字,如果下划线可以改善可读性可以加入,例如:mypackage。

  • 模块
  • 使用简短的小写的名字,如果下划线可以改善可读性可以加入,例如:如mymodule。

  • 总是使用首字母大写单词串。如MyClass。内部类可以使用额外的前导下划线。

  • 函数和方法
  • 函数名应该为小写,可以用下划线风格单词以增加可读性。如:myfunction,my_example_function。

  • 函数和方法的参数
  • 总使用“self”作为范例方法的第一个参数。总使用“cls”作为类方法的第一个参数。

    如果一个函数的参数名称和保留的关键字冲突,通常使用一个后缀下划线好于使用缩写或奇怪的拼写。

  • 全局变量
  • 对于from M import *导入语句,如果想阻止导入模块内的全局变量可以使用旧有的规范,在全局变量上加一个前导的下划线。

    *注意*:应避免使用全局变量

  • 变量
  • 变量名全部小写,由下划线连接各个单词。如color = WHITE,this_is_a_variable = 1。

    *注意*:

    1.不论是类成员变量还是全局变量,均不使用 m 或 g 前缀。

    2.私有类成员使用单一下划线前缀标识,多定义公开成员,少定义私有成员。

    3.变量名不应带有类型信息,因为Python是动态类型语言。如 iValue、names_list、dict_obj 等都是不好的命名。

  • 常量
  • 常量名所有字母大写,由下划线连接各个单词。例如:MAX_OVERFLOW、TOTAL。

  • 异常
  • 以“Error”作为后缀。
  • 前导后缀下划线
  • 1.一个前导下划线:表示变量或者方法非公有。

    2.一个后缀下划线:避免关键字冲突。

    3.两个前导下划线:当命名一个类属性引起名称冲突时使用。

    4.两个前导和后缀下划线:内部有特殊用途的对象或者属性,例如__init__或者__file__。绝对不要创造这样的名字,而只是使用它们。

2. 缩进

使用4个空格来缩进代码,不要使用tab,也不要混用tab和空格。

对于行连接的情况, 你应该要么垂直对齐换行的元素,或者使用4空格的悬挂式缩进(这时第一行不应该有参数):

正确:   
# 与起始变量对齐
foo = long_function_name(var_one, var_two,
                        var_three, var_four)

# 字典中与起始值对齐
foo = {
   long_dictionary_key: value1 +
                        value2,
   ...
}

# 4 个空格缩进,第一行不需要
foo = long_function_name(
   var_one, var_two, var_three,
   var_four)

# 字典中 4 个空格缩进
foo = {
   long_dictionary_key:
       long_dictionary_value,
   ...
}

3. 分号

不要在行尾加分号, 也不要用分号将两条命令放在同一行。

4. 行长度

  • 每行不超过80个字符,其中长的导入模块语句和注释里的URL除外
  • 不要使用反斜杠连接行。Python会将圆括号, 中括号和花括号中的行隐式的连接起来
  • 正确: 
    foo_bar(self, width, height, color='black', design=None, x='foo',
            emphasis=None, highlight=0)
    
  • 如果一个文本字符串在一行放不下, 可以使用圆括号来实现隐式行连接:
  • x = ('这是一个非常长非常长非常长非常长 '
        '非常长非常长非常长非常长非常长非常长的字符串')
    
  • 在注释中,如果必要,将长的URL放在一行上。
  • # See details at
    # http://www.example.com/us/developer/documentation/api/content/v2.0/csv_file_specification.html
    

5. 括号

宁缺毋滥的使用括号,除非是用于实现行连接, 否则不要在返回语句或条件语句中使用括号,不过在元组两边使用括号是可以的。

正确: 
if foo:
    bar()
while x:
    x = bar()
if x and y:
    bar()
if not x:
    bar()
return foo
for (x, y) in dict.items(): ...
     
错误:
if (x):
    bar()
if not(x):
    bar()
return (foo)

6. 空行

顶级定义之间空2行,比如函数或者类定义。方法定义之间空1行。

方法定义、类定义与第一个方法之间,都应该空1行。函数或方法中,某些地方觉得合适就空一行。

7. 空格

  • 按照标准的排版规范来使用标点两边的空格,括号内不要有空格,按照标准的排版规范来使用标点两边的空格
  • 正确: spam(ham[1], {eggs: 2}, [])
    错误: spam( ham[ 1 ], { eggs: 2 }, [ ] )	
    
  • 不要在逗号、分号、冒号前面加空格,但应该在它们后面加(除了在行尾)
  • 正确:
    if x == 4:
        print x, y
        x, y = y, x
    错误: 
    if x == 4 :
        print x , y
        x , y = y , x
    
  • 参数列表,索引或切片的左括号前不应加空格
  • 正确: spam(1)
    错误: spam (1)
    正确: dict['key'] = list[index]
    错误: dict ['key'] = list [index]
    
  • 在二元操作符两边都加上一个空格,比如赋值(=)、比较(==, <, >, !=, <>, <=, >=, in, not in, is, is not)、布尔(and, or, not)。至于算术操作符两边的空格该如何使用,需要你自己好好判断,不过两侧务必要保持一致。
  • 正确: x == 1
    错误: x<1
    
  • 当’='用于指示关键字参数或默认参数值时,不要在其两侧使用空格。
  • 正确: def complex(real, imag=0.0): return magic(r=real, i=imag)
    错误: def complex(real, imag = 0.0): return magic(r = real, i = imag)
    
  • 不要用空格来垂直对齐多行间的标记,因为这会成为维护的负担(适用于:, #, =等)
  • 正确: 
    foo = 1000  # 注释
    long_name = 2  # 注释不需要对齐
    dictionary = {
        "foo": 1,
        "long_name": 2,
        }
    
    错误: 
    foo       = 1000  # 注释
    long_name = 2     # 注释不需要对齐
    dictionary = {
        "foo"      : 1,
        "long_name": 2,
        }
    

8. 注释

  • 文档字符串
  • Python有一种注释方式: 使用文档字符串。文档字符串是包、模块、类或函数里的第一个语句。这些字符串可以通过对象的__doc__成员被自动提取,并且被pydoc所用。

    对文档字符串的惯例是使用三重双引号"""。

  • 函数和方法:
  • 每节应该以一个标题行开始,标题行以冒号结尾。除标题行外, 节的其他内容应被缩进2个空格。

    列出每个参数的名字,并在名字后使用一个冒号和一个空格,分隔对该参数的描述.如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致)。描述应该包括所需的类型和含义。如果一个函数接受foo(可变长度参数列表)或者**bar (任意关键字参数), 应该详细列出foo和**bar。

    Returns: (或者 Yields: 用于生成器)

    描述返回值的类型和语义。 如果函数返回None, 这一部分可以省略。

    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.
        """
        pass
    
  • 类应该在其定义下有一个用于描述该类的文档字符串。如果你的类有公共属性(Attributes),那么文档中应该有一个属性(Attributes)段,并且应该遵守和函数参数相同的格式。

    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."""
    
  • 块注释和行注释
  • 最需要写注释的是代码中那些技巧性的部分。如果你在下次 代码审查 的时候必须解释一下,那么你应该现在就给它写注释。对于复杂的操作,应该在其操作开始前写上若干行注释。对于不是一目了然的代码,应在其行尾添加注释。为了提高可读性,注释应该至少离开代码2个空格。

    # 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 iff i is a power of 2
    

9. 类 class

如果一个类不继承自其它类,就显式的从object继承,嵌套类也一样。

class SampleClass(object):
    pass


class OuterClass(object):
    class InnerClass(object):
        pass


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

继承自 object 是为了使属性正常工作,并且这样可以保护你的代码,使其不受Python 3000的一个特殊的潜在不兼容性影响。这样做也定义了一些特殊的方法(魔法方法),这些方法实现了对象的默认语义,包括 new, init, delattr, getattribute, setattr, hash, repr, and str。

10. 导入 import

每个导入应该独占一行

正确: 
import os
import sys
错误: 
import os, sys

导入总应该放在文件顶部,位于模块注释和文档字符串之后,模块全局变量和常量之前。

导入应该按照从最通用到最不通用的顺序分组:

  • 标准库导入
  • 第三方库导入
  • 应用程序指定导入

每种分组都应该根据每个模块的完整包路径按字典序排序,忽略大小写。

import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar

11. 语句

通常每个语句应该独占一行。不过,如果测试结果与测试语句在一行放得下,也可以将它们放在同一行。

如果是if语句,只有在没有else时才能这样做。 特别地,绝不要对 try/except 这样做, 因为try和except不能放在同一行。

正确:
if foo: bar(foo)
  
错误:
if foo: bar(foo)
else:   baz(foo)

try:               bar(foo)
except ValueError: baz(foo)