python编写规范
一、说明
二、内容
1. 代码布局
1.1 缩进
1.2 表达式和语句中的空格
1.3 行的最大长度
1.4 空行...
1.5 编码...
2. 语句...
2.1 标准头部...
2.2 导入(import)...
2.3 赋值...
2.4 分支和循环...
3. 注释...
3.1 注释块...
3.2 行内注释...
3.3 文档字符串...
3.4 版本注记...
3.5 模块注释...
3.6 函数和方法注释...
3.7 类注释...
4. 命名约定...
4.1 说明:命名约定...
4.2 模块名...
4.4 类名...
4.5 异常名...
4.6 变量、常量、全局变量名...
4.7 函数名...
4.8 方法名和实例变量...
4.9 特定的命名方式...
5. 继承的设计...
6. 设计建议...
一、 说明
为了规范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: /* **历史修改记录** */*
* *
*fei.liu 2013-03-04 1.0 Release*
*"""*
__authors__ = [
*'"John Smith" '*,
*'"Joe Paranoid" '*,
]
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: