python项目代码规范
一、序
说明
为了团队开发的高效性与项目后续的可维护性,所有开发人员在进行开发时,都徐尽可能的遵守本规范。
凡是参与项目开发的人都应阅读此文档。也同时作为代码审查的标准之一。
本文所述规范有以下级个级别,
【建议】
【必须】
章节安排
本片代码规范主要分为以下几个方面:
- 变量及常量规范
- 函数规范
- 注释规范
- 类的规范
- 其他规范
二、变量及常量规范
- 使用英文含义进行命名,禁止使用汉英结合或自创英文【必须】
命名——常量
- 常量命名应使用大写字母加下划线的方式【建议】
- 尽可能少在代码区出现常量。【建议】
正确示例
if days>YEAR_DAYS:
return 'more than a year'
错误示例
if days>365:
return 'more than a year'
- 仅在一个文件中使用的常量,声明在文件开头。【建议】
正确示例
import datetime
BASE_DIR =os.getcwd()
- 在多个文件中使用的常量,使用配置文件统一配置。【建议】
正确示例
import Config
if days>Config.YEAR_DAYS:
return 'more than a year'
命名——变量
- 统一使用下划线命名或驼峰命名,但不可混用。【必须】
正确示例
user_info_list#下划线命名
userInfoList#驼峰命名
- 复杂类型的变量应注名类型【建议】
confirmBtn=Button()
user_dict={}
- Boolon类型变量应使用is或has开头命名【建议】
- 禁止仅使用类型对变量进行命名。【必须】
正确示例
user_names=[]
错误示例
_list=[]
- 禁止使用单个字母或无意义的符号【必须】
错误示例
l=[]
for i in a:
l.append(i)
特例:允许i,j等字母仅当做【索引】时使用
正确示例
for i,name in enumrate(names):
pass
特例:允许将后文不绝不会被使用的函数返回值或迭代器返回值命名为‘_’
正确示例
for _,sex,name in persons:
clone=Person(sex,name)
- 建议不要使用过于简略的缩写,除非这种缩写广为人知【建议】
错误示例
pad=PersonalAddressDetail()
正确示例
msg=getMessage()
ack=sendRequest()
声明及使用
- 禁止使用未经声明的变量【必须】
- 尽可能不声明从来不被使用的变量【强烈建议】
特例:防止GC回收内存时可以
三、函数规范
函数命名
- 函数命名必须要正确反应函数功能,除此功能外禁止做其他事情【必须】
如果感觉无法对其准确命名,很有可能是该函数功能过于繁杂。参见函数定义
- 函数命名应使用动词短语的形式进行命名【建议】
正确示例
def getUserInfo()
pass
错误示例
def userInfo()
pass
- 建议标明函数形式参数和返回值的类型【建议】
def getPerson(name:str,sex:SexEnum)->Person:
pass
函数定义
- 函数要坚持单一功能的原则,一个函数只干一件事情,并且要与命名相一致【建议】
错误示例
def getPersonInfo(person):
person=psersonService.getPerson()
person.setNewName(“xxx”)#从getPersonInfo()的命名中无法得知会进行如此操作
return person
- 单个函数的长度最长不要超过40行【建议】
- 函数声明与定义中,禁止出现函数体中从来不会使用到的形参【必须】
注释规范
- 注释应尽可能说明"为什么"而不是"是什么",解释代码中那些技巧性的部分,而不是描述代码【建议】
错误示例
def getUserByName(name:str)->User:#通过姓名获取用户
pass
正确示例
def getUserByName(name:str)->User:#向用户隐藏ID字段,使用name也可获得用户信息
if i & (i-1) == 0: # i等于0或i为2的幂
- 自定义的字典、列表等复杂数据结构应在注释中说明【建议】
- 设计思路、特殊用意、需求也可以在注释中说明【建议】
- 复杂或公共函数的注释应表明函数参数含义,返回值含义以及可能会抛出的各类异常【建议】
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 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
三、类的规范
类的命名
- 类命名统一使用首字母大写的驼峰命名方法【建议】
类的定义
- 如果一个类不继承自其它类, 就显式的从object继承. 嵌套类也一样.【建议】
正确示例
class SampleClass(object):
pass
class OuterClass(object):
class InnerClass(object):
pass
class ChildClass(ParentClass):
pass
错误示例
class SampleClass:
pass
class OuterClass:
class InnerClass:
pass
继承自
object
是为了使属性(properties)正常工作, 并且这样可以保护你的代码, 使其不受 PEP-3000 的一个特殊的潜在不兼容性影响. 这样做也定义了一些特殊的方法, 这些方法实现了对象的默认语义, 包括__new__, __init__, __delattr__, __getattribute__, __setattr__, __hash__, __repr__, and __str__
- 符合封装的开闭原则,不要把不必要的方法访问权限全部设置为public【建议】
- 避免使用双下划线开头并结尾的名称(Python保留, 例如__init__)【必须】
- 接口类的函数定义应使用
raise UnimplamentException
而不是pass
【建议】
四、其他规范
- 避免在循环中用+和+=操作符来累加字符串,【建议】
由于字符串是不可变的, 这样做会创建不必要的临时对象, 并且导致二次方而不是线性的运行时间. 作为替代方案, 你可以将每个子串加入列表, 然后在循环结束后用
.join
连接列表
- 尽可能不要使用
from modeules import *
的写法,而是具体到要导入的函数或变量【强烈建议】 - 在同一个文件中, 保持使用字符串引号的一致性. 使用单引号’或者双引号”之一用以引用字符串【建议】
- 对于Exception的捕获,应使用as捕获具体的错误类型。【强烈建议】
正确示例
try:
person=person_dict[name]
except ValueError as e:
pass#Normal error,do nothing
except Exception as e:
raise e
错误示例
try:
person=person_dict[name]
except:
pass#Normal error,do nothing
- 不要使用太复杂的列表生成器,过于复杂是请使用循环【建议】
错误示例
names=[
(x,y,z) for x in xs
for y in ys if x != y
for z in zs if z != y
]