一、 说明
为了规范Python代码的书写,提高代码的可读性,使编码人员在代码上更好的协作,制定了本规范。
中标软件有限公司测试中心员工在编写Python代码时,必须遵守本规范。如对规范有异议,请联系维护人员。
编码规范的作用:
提高可读性 ——“任何一个傻瓜都能写出计算机可以理解的代码,唯有写出人类容易理解的代码,才是优秀的程序员。”编码规范,帮助我们写出人类容易理解的代码。
统一全局,促进团队协作—— 开发是一个团队活动,而不是个人的英雄主义。
有助于知识传递,加快工作交接 ——风格的相似性,能让编码人员更迅速,更容易理解一些陌生的代码,更快速地理解别人的代码。
减少名字增生,降低维护成本 ——在没有规范的情况下,很容易为同一类型的实例起不同的名字。
强调变量之间的关系,降低缺陷引入的机会 ——命名可以表示一定的逻辑关系,使开发人员在使用时保持警惕,从而一定程度上减少缺陷被引入的机会。
提高个人能力 。
二、 内容
1. 代码布局
1.1 缩进
推荐以4个空格作为一个缩进层次。
1.2 表达式和语句中的空格
1. 前导空格(缩进)
最流行的Python缩进方式是仅使用空格,其次是仅使用制表符。对于新的项目,应该仅使用空格而不是制表符。
2. 非前导空格
非前导空格在Python代码中没有意义,但适当地加入非前导空格可以增进代码可读性:
(1)在二元算术、逻辑运算符前后加空格,如:
示例:
a = b + c
if a and b:
pass
(2)在一元前缀运算符后不加空格,如:
示例:
if !flg:
pass
(3)“:”用在行尾时前后皆不加空格,如分支、循环、函数和类定义语言;用在非行尾时后端加空格,如dict对象的定义:
示例:
d = {'key': 'value'}
(4)括号(含圆括号、方括号和花括号)前后不加空格,如:
示例:
do_something(arg1, arg2)
(5)逗号后面加一个空格,前面不加空格。
1.3 行的最大长度
每行的最大长度不得超过80个字符的标准。超过80个字符的,建议使用以下方式将单个长行折叠成多个短行:
(1)为长变量名换一个短名,如:
错误写法:
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)在括号(包括圆括号、方括号和花括号)内的分隔符后换行,如:
示例:
class Edit(Base):
def __init__(self, parent, width,
font = FONT, color = BLACK, pos = POS, style = 0): # 注意:此行与上一行保持同样缩进
pass
(3)在长行加入续行符强行断行,断行的位置应在操作符前,如:
示例:
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格式:
#-*- coding:utf8 -*-
2. 语句
2.1 标准头部
一般情况下使用如下标准头部语句:
#!/usr/bin/python
如果需要使用自定义的Python编译环境,可使用类似如下的头部语句:
#!/usr/bin/env python2.7
说明:该行语句的作用是帮助内核找到Python解释器,但通常在Python导入模块时被忽略;只有直接执行单个文件时,该语句才是必要的。
2.2 导入(import)
1. 通常应该在单独的行中导入(import),例如“正确写法1”;若需要在一行中从一个模块导入多个类,可参照“正确写法2”:
错误写法:
import sys, os
正确写法1:
import sys
import os
正确写法2:
from types import StringType, ListType
2. 导入语句的位置及导入顺序
通常将import语句放置在文件的顶部,仅在模块注释和文档字符串之后,在模块的全局变量和常量之前。导入语句应该有顺序地成组安放:
(1)首先,导入标准库(内置模块);
(2)其次,导入第三方模块(引用的第三方包);
(3)最后,导入自己开发的项目中的其他模块;
在每组导入之间放置一个空行。
3. 导入类的方法
从一个包含类的模块中导入类时,通常可以写成这样:
示例:
from MyClass import MyClass
from foo.bar.YourClass import YourClass
如果上述写法导致了本地名字冲突,那么就这样写:
示例:
import MyClass
import foo.bar.YourClass
然后使用MyClass.MyClass和foo.bar.YourClass.YourClass方式即可。
2.3 赋值
对于赋值语言,主要是不要做无谓的对齐,如:
错误写法:
a = 1
var = 2
fn = callback_function
正确写法:
a = 1
var = 2
fn = callback_function
2.4 分支和循环
各种分支和循环语句不要写成一行,如:
错误写法:
if !flg: pass
for i in xrange(10): print i
正确写法:
if !flg:
pass
for i in xrange(10):
print i
3. 注释
代码修改时,始终优先更新注释。注释应该是完整的句子,如果注释是一个短语或句子,首字母应该大写,除非他是一个以小写字母开头的标识符(如果以中文注释可忽略此要求)。
3.1 注释块
注释块通常用于跟随着一些代码并和这些代码有着相同的缩进层次。注释块中每行均以“#”和一个空格开始。注释块内的段落间以仅含单个“#”的行分割。注释块上下方最好各有一空行。
3.2 行内注释
行内注释是和语句在同一行的注释。行内注释应该至少用两个空格和语句分开,且应该以“#”和单个空格开始,如:
示例:
x = x + 1 # Increment x
如果语意很明了,那么行内注释则不必要。
3.3 文档字符串
为所有公共模块、函数、类和方法编写文档字符串。文档字符串对非公开的方法不是必要的,但应该有一个注释描述这个方法的作用。这个注释应该在“def”行之后。
一定注意,多行文档字符串结尾的"""应该单独成行,例如:
示例:
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first
"""
对单行的文档字符串,结尾的"""在同一行也可以,例如:
"""Return a foobang"""
3.4 版本注记
版本注记可以参照如下示例代码:
示例:
__version__ = "$Revision: 1.4 $"
这行应该包含在模块的文档字符串之后,所有代码之前,上下用一个空行分割。
3.5 模块注释
每个模块注释都应该包含下列项,依次是:
(1)版权声明;
(2)模块注释内容,包括模块描述、模块中的类和方法的描述、版本及维护信息等;
(3)作者声明,标识文件的原作者;
示例:
# 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:应该列出该函数可能触发的所有异常;
示例:
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),那么文档字符串中应该说明这些公共属性的意义。
示例:
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. 命名约定
4.1 说明:命名约定
禁止使用字符“l”、“O”或“I”作为单字符的变量名。在某些字体中无法将这些字符与数字1和0区分开。
4.2 模块名
模块名应该是不含下划线的、简短的、全小写的名字;对于默认仅在包(Packages)内使用的模块,可以加一个下划线前缀,如:
示例:
module.py
_internal_module.py
4.4 类名
类名使用CapWords约定(单词首字母大写,不使用下划线连接单词,也不加入C、T等前缀);内部使用的类需要在名称前加一个前导下划线,如:
示例:
class ThisIsAClass(object):
pass
class _ThisIsAClass(object):
pass
4.5 异常名
异常名使用CapWords命名规则(单词首字母大写,不使用下划线连接单词)。
4.6 变量、常量、全局变量名
Python一般通过“from M import *”来从模块中导入相关内容(变量、类、函数等),必须用一个下划线作全局变量(内部函数或类)的前缀防止其被导出(exporting)。
1. 常量
常量名的所有字母均大写,由下划线连接各个单词,如:
示例:
WHITE = 0XFFFFFF
THIS_IS_A_CONSTANT = 1
2. 变量
(1)变量名全部小写,由下划线连接各个单词,如:
示例:
color = WHITE
this_is_a_variable = 1
(2)不论是类成员变量还是全局变量,均不使用m或g前缀。私有类成员使用单一下划线前缀标识;
(3)变量名不应带有类型信息,因为Python是动态类型语言;如iValue、names_list、dict_obj等都是不好的命名。
3. 全局变量
必须用一个下划线作为全局变量的前缀防止其被导出。
4.7 函数名
函数名应该为小写,可用下划线风格单词以增加可读性。
4.8 方法名和实例变量
大体上和函数命名规则相同:通常使用小写单词,必要时用下划线分隔增加可读性。
如果是不打算对外公开的内部方法和实例,需要在名称开头使用一个前导下划线。
使用两个前导下划线以表示类私有成员的名字。通常双前导下划线仅被用于避免含子类的类中的属性名冲突。
4.9 特定的命名方式
主要是指__xxx__形式的系统保留字命名法。项目中也可以使用这种命名,它的意义在于这种形式的变量是只读的,这种形式的类成员函数尽量不要重载。如:
示例:
class Base(object):
def __init__(self, id, parent = None):
self.__id__ = id
self.__parent__ = parent
def __message__(self, msgid):
# ...
其中__id_、__parent__和__message__都采用了系统保留字命名法。
5. 继承的设计
始终要确定一个类中的方法和实例变量是否要被公开。通常,永远不要将数据变量公开,除非你实现的本质上只是记录,人们总是更喜欢为类提供一个函数的接口来实现数据变量的修改。
同样,确定你的属性是否应为私有的。私有和非私有的区别在于:前者永远不会被用在一个派生类中,而后者可能会。你应该在大脑中就用继承设计好了你的类:(1)私有属性必须有两个前导下划线,无后置下划线;(2)非公有属性必须有一个前导下划线,无后置下划线;(3)公共属性没有前导和后置下划线,除非它们与保留字冲突,在此情况下,单个后置下划线比前置或混乱的拼写要好,例如:class_优于klass。
6. 设计建议
单个元素(singletons)的比较,如None应该使用“is”或“is not”。当你本意是“if x is not None”时,对写成“if x”要小心。例如当你测试一个默认为None的变量或参数是否被设置为其它值时,这个其它值也许在布尔上下文(Boolean context)中是False。
基于类的异常总是好过基于字符串的异常。模块和包应该定义它们自己的域内特定的基异常类,基类应该是内建的Exception类的子类,还始终包含一个类的文档字符串。例如:
示例:
#!/usr/bin/Python
class(Exception):
"""Base class for errors in the email package."""
MessageError
使用字符串方法(methods)代替字符串模块,除非必须向后兼容Python 2.0以前的版本。字符串方法总是非常快,而且和unicode字符串共用同样的API(应用程序接口),在检查前缀或后缀时避免对字符串进行切片。用startswith()和endswith()代替,因为这样出现错误的机率更小。例如:
错误写法:
if foo[:3] == 'bar':
正确写法:
if foo.startswith('bar'):
特殊情况下,如果你的代码必须工作在Python 1.5.2,对象类型的比较应该始终用isinstance()代替直接比较类型,例如:
错误写法:
if type(obj) is type(1):
正确写法:
if isinstance(obj, int):
检查一个对象是否是字符串时,谨记它也可能是unicode字符串!在Python 2.3中,str和unicode有公共的基类basestring,所以你可以这样做:
if isinstance(obj, basestring):
在Python 2.2类型模块为此定义了StringTypes类型,例如:
#!/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中新增的):
错误写法:
if greeting == True:
正确写法:
if greeting:
网友评论