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
]