python开发规范简单记录

python开发规范(转载自:https://www.cnblogs.com/cwp-bg/p/9827529.html)

代码布局

1.1缩进

推荐以4个空格作为一个缩进层次。

1.2表达式和语句中的空格

1.2.1 前导空格(缩进)

最流行的Python缩进方式是仅使用空格,其次是仅使用制表符。对于新的项目,应该仅使用空格而不是制表符。

1.2.2 非前导空格

非前导空格在Python代码中没有意义,但适当地加入非前导空格可以增进代码可读性:
(1)在二元算术、逻辑运算符前后加空格,如:

1
2
3
a = b + c
if a and b:
pass

(2)在一元前缀运算符后不加空格,如:

1
2
if !flag:
pass

(3)“:”用在行尾时前后皆不加空格,如分支、循环、函数和类定义语言;用在非行尾时后端加空格,如dict对象的定义:

1
d = {'key': 'value'}

(4)括号(含圆括号、方括号和花括号)前后不加空格,如:

1
do_something(arg1, arg2)

(5)逗号后面加一个空格,前面不加空格。

1.3行的最大长度

每行的最大长度不得超过80个字符的标准。超过80个字符的,建议使用以下方式将单个长行折叠成多个短行:
(1)为长变量名换一个短名,如:

1
2
3
4
5
6
7
8
9
10
11
错误写法:

this.is.a.very.long.variable_name = this.is.another.long.variable_name

正确写法:

variable_name1 = this.is.a.very.long.variable_name

variable_name2 = this.is.another.variable_name

variable_name1 = variable_name2

(2)在括号(包括圆括号、方括号和花括号)内的分隔符后换行,如:

1
2
3
4
5
6
7
示例:
class Edit(Base):

def __init__(self, parent, width,

font = FONT, color = BLACK, pos = POS, style = 0): # 注意:此行与上一行保持同样缩进
pass

(3)在长行加入续行符强行断行,断行的位置应在操作符前,如:

1
2
3
4
5
if color == WHITE or color == BLACK \

or color == BLUE: # 注意:换行与首行保持同样的缩进(或均不缩进)

do_something(color)

1.4空行

输入空行时,一般遵循以下原则:

(1)在import不同种类的模块间加空行;

(2)顶层函数和类的定义之间加空行;

(3)在类与类的定义之间加空行;

(4)在函数与函数的定义之间加空行;

(5)在class定义行和其第一个方法定义之间加空行;

(6)在函数中的逻辑段落间加空行,即把相关的代码紧凑写在一起,作为一个逻辑段落,段落间以空行分隔。

1.5编码

所有的Python脚本文件都应在文件头标上#– coding:utf8 — ;用于设置编辑器,默认保存为utf8格式:

1
#-*- coding:utf8 -*-

语句

2.1标准头部

一般情况下使用如下标准头部语句:

1
#!/usr/bin/python

如果需要使用自定义的Python编译环境,可使用类似如下的头部语句:

1
#!/usr/bin/env python2.7

说明:该行语句的作用是帮助内核找到Python解释器,但通常在Python导入模块时被忽略;只有直接执行单个文件时,该语句才是必要的。

2.2导入(import)

2.2.1通常应该在单独的行中导入(import)

例如“正确写法1”;若需要在一行中从一个模块导入多个类,可参照“正确写法2”:

1
2
3
4
5
6
7
8
9
10
11
12
13
错误写法:

import sys, os

正确写法1

import sys

import os

正确写法2

from types import StringType, ListType

2.2.2导入语句的位置及导入顺序

通常将import语句放置在文件的顶部,仅在模块注释和文档字符串之后,在模块的全局变量和常量之前。导入语句应该有顺序地成组安放:

(1)首先,导入标准库(内置模块);

(2)其次,导入第三方模块(引用的第三方包);

(3)最后,导入自己开发的项目中的其他模块;

在每组导入之间放置一个空行。

2.2.3导入类的方法

从一个包含类的模块中导入类时,通常可以写成这样:

1
2
3
4
5
示例:

from MyClass import MyClass

from foo.bar.YourClass import YourClass

如果上述写法导致了本地名字冲突,那么就这样写:

1
2
3
4
5
示例:

import MyClass

import foo.bar.YourClass

然后使用MyClass.MyClass和foo.bar.YourClass.YourClass方式即可。

2.3赋值

对于赋值语言,主要是不要做无谓的对齐,如:

本文采用 CC NONE 4.0 许可协议,著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
错误写法:

a = 1

var = 2

fn = callback_function

正确写法:

a = 1

var = 2

fn = callback_function

2.4分支和循环

各种分支和循环语句不要写成一行,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
错误写法:

if !flg: pass

for i in xrange(10): print i

正确写法:

if !flg:

pass

for i in xrange(10):

print i

注释

代码修改时,始终优先更新注释。注释应该是完整的句子,如果注释是一个短语或句子,首字母应该大写,除非他是一个以小写字母开头的标识符(如果以中文注释可忽略此要求)。

3.1注释块

注释块通常用于跟随着一些代码并和这些代码有着相同的缩进层次。注释块中每行均以“#”和一个空格开始。注释块内的段落间以仅含单个“#”的行分割。注释块上下方最好各有一空行。

3.2行内注释

行内注释是和语句在同一行的注释。行内注释应该至少用两个空格和语句分开,且应该以“#”和单个空格开始,如:

1
2
3
示例:

x = x + 1 # Increment x

3.3文档字符串

为所有公共模块、函数、类和方法编写文档字符串。文档字符串对非公开的方法不是必要的,但应该有一个注释描述这个方法的作用。这个注释应该在“def”行之后。

一定注意,多行文档字符串结尾的”””应该单独成行,例如:

1
2
3
4
5
6
7
示例:

"""Return a foobang

Optional plotz says to frobnicate the bizbaz first

"""

对单行的文档字符串,结尾的”””在同一行也可以,例如:

1
"""Return a foobang"""

3.4版本注记

版本注记可以参照如下示例代码:

1
2
3
4
5
示例:

__version__ = "$Revision: 1.4 $"

这行应该包含在模块的文档字符串之后,所有代码之前,上下用一个空行分割。

3.5模块注释

每个模块注释都应该包含下列项,依次是:

(1)版权声明;

(2)模块注释内容,包括模块描述、模块中的类和方法的描述、版本及维护信息等;

(3)作者声明,标识文件的原作者;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
示例:

# Copyright (C), 2010-2013, China Standard Software Co., Ltd.

"""

FileName: Test.py

Author: fei.liu

Version: 0.1

Date: 2013-02-27

Description: 用一行文字概述模块或脚本,用句号结尾。

ClassFoo: 一行概述该模块中的类的用途。

functionBar(): 一行概述该模块中的函数的用途。

History: /* 历史修改记录 */

<Author> <Date> <Version> <Desc>

fei.liu 2013-03-04 1.0 Release

"""

__authors__ = [

'"John Smith" <johnsmith@example.com>',

'"Joe Paranoid" <joeisgone@example.com>',

]

3.6函数和方法注释

任何函数或方法都需要一个文档字符串,对于任何外部可访问的函数或方法,文档字符串尤为重要。

文档字符串应该包含函数的作用,以及参数、输入和输出的详细描述:

(1)Args:输入参数的具体描述;如果参数要求特定的数据类型或者设置了参数的默认值,那么应该在文档字符串中明确说明;

(2)Returns:输出(返回)数据的具体描述;

(3)Raises:应该列出该函数可能触发的所有异常;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
示例:

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):

"""取出表格中的多行内容

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 rowto 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

3.7类注释

类定义下方必须有一个用于描述该类的文档字符串(docString)。如果类中有公共属性(Attributes),那么文档字符串中应该说明这些公共属性的意义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
示例:

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."""

命名约定

4.1说明:命名约定

禁止使用字符“l”、“O”或“I”作为单字符的变量名。在某些字体中无法将这些字符与数字1和0区分开。

4.2模块名

模块名应该是不含下划线的、简短的、全小写的名字;对于默认仅在包(Packages)内使用的模块,可以加一个下划线前缀,如:

1
2
3
4
5
示例:

module.py

_internal_module.py

4.4类名

类名使用CapWords约定(单词首字母大写,不使用下划线连接单词,也不加入C、T等前缀);内部使用的类需要在名称前加一个前导下划线,如:

1
2
3
4
5
6
7
8
9
示例:

class ThisIsAClass(object):

pass

class _ThisIsAClass(object):

pass

4.5异常名

异常名使用CapWords命名规则(单词首字母大写,不使用下划线连接单词)。

4.6变量、常量、全局变量名

Python一般通过“from M import *”来从模块中导入相关内容(变量、类、函数等),必须用一个下划线作全局变量(内部函数或类)的前缀防止其被导出(exporting)。

4.6.1常量

常量名的所有字母均大写,由下划线连接各个单词,如:

1
2
3
4
5
示例:

WHITE = 0XFFFFFF

THIS_IS_A_CONSTANT = 1

4.6.2变量

(1)变量名全部小写,由下划线连接各个单词,如:

1
2
3
4
5
示例:

color = WHITE

this_is_a_variable = 1

(2)不论是类成员变量还是全局变量,均不使用m或g前缀。私有类成员使用单一下划线前缀标识;

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

4.6.3全局变量

必须用一个下划线作为全局变量的前缀防止其被导出。

4.7函数名

函数名应该为小写,可用下划线风格单词以增加可读性。

4.8方法名和实例变量

大体上和函数命名规则相同:通常使用小写单词,必要时用下划线分隔增加可读性。

如果是不打算对外公开的内部方法和实例,需要在名称开头使用一个前导下划线。

使用两个前导下划线以表示类私有成员的名字。通常双前导下划线仅被用于避免含子类的类中的属性名冲突。

4.9特定的命名方式

主要是指__xxx__形式的系统保留字命名法。项目中也可以使用这种命名,它的意义在于这种形式的变量是只读的,这种形式的类成员函数尽量不要重载。如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
示例:

class Base(object):

def __init__(self, id, parent = None):

self.__id__ = id

self.__parent__ = parent

def __message__(self, msgid):

# ...

其中__id_、__parent__和__message__都采用了系统保留字命名法。

继承的设计

始终要确定一个类中的方法和实例变量是否要被公开。通常,永远不要将数据变量公开,除非你实现的本质上只是记录,人们总是更喜欢为类提供一个函数的接口来实现数据变量的修改。

同样,确定你的属性是否应为私有的。私有和非私有的区别在于:前者永远不会被用在一个派生类中,而后者可能会。你应该在大脑中就用继承设计好了你的类:
(1)私有属性必须有两个前导下划线,无后置下划线;
(2)非公有属性必须有一个前导下划线,无后置下划线;
(3)公共属性没有前导和后置下划线,除非它们与保留字冲突,在此情况下,单个后置下划线比前置或混乱的拼写要好,例如:class_优于klass。

设计建议

单个元素(singletons)的比较,如None应该使用“is”或“is not”。当你本意是“if x is not None”时,对写成“if x”要小心。例如当你测试一个默认为None的变量或参数是否被设置为其它值时,这个其它值也许在布尔上下文(Boolean context)中是False。

基于类的异常总是好过基于字符串的异常。模块和包应该定义它们自己的域内特定的基异常类,基类应该是内建的Exception类的子类,还始终包含一个类的文档字符串。例如:

1
2
3
4
5
6
7
8
示例:

#!/usr/bin/Python
class(Exception):

"""Base class for errors in the email package."""

MessageError

使用字符串方法(methods)代替字符串模块,除非必须向后兼容Python 2.0以前的版本。字符串方法总是非常快,而且和unicode字符串共用同样的API(应用程序接口),在检查前缀或后缀时避免对字符串进行切片。用startswith()和endswith()代替,因为这样出现错误的机率更小。例如:

1
2
3
4
5
6
7
错误写法:

if foo[:3] == 'bar':

正确写法:

if foo.startswith('bar'):

特殊情况下,如果你的代码必须工作在Python 1.5.2,对象类型的比较应该始终用isinstance()代替直接比较类型,例如:

1
2
3
4
5
6
7
错误写法:

if type(obj) is type(1):

正确写法:

if isinstance(obj, int):

检查一个对象是否是字符串时,谨记它也可能是unicode字符串!在Python 2.3中,str和unicode有公共的基类basestring,所以你可以这样做:

1
if isinstance(obj, basestring):

在Python 2.2类型模块为此定义了StringTypes类型,例如:

1
2
3
4
5
#!/usr/bin/Python

from types import StringTypes

if isinstance(obj, StringTypes):

对序列(字符串、列表、元组)而言,使用空列表是false这个事实,因此“if not seq”或“if seq”比“if len(seq)”或“if not len(seq)”好。书写字符串文字时不要依赖于有意义的后置空格。这种后置空格在视觉上是不可辨别的,并且有些编辑器会将它们修整掉。不要用“==”来比较布尔型的值以确定是True或False(布尔型是Python2.3中新增的):

1
2
3
4
5
6
7
错误写法:

if greeting == True:

正确写法:

if greeting: