自动摘要: 代码类型注释 你可以根据PEP484来对python3代码进行注释,并使用诸如[pytyp ……..
代码类型注释
你可以根据 PEP-484 来对 python3 代码进行注释,并使用诸如 pytype 之类的类型检查工具来检查代码.类型注释既可以写在源码,也可以写在 pyi 中.推荐尽量写在源码里,对于第三方扩展包,可以写在pyi文件里.
定义:用于函数参数和返回值的类型注释:
1 | def func(a: int) -> List[int]: |
也可以使用 PEP-526 中的语法来声明变量类型:
1 | a: SomeType = some_func() |
在必须支持老版本 python 运行的代码中则可以这样注释:
1 | a = some_func() #type: SomeType |
优点:可以提高代码可读性和可维护性.同时一些类型检查器可以帮您提早发现一些运行时错误,并降低您使用大威力特性的必要.
缺点:必须时常更新类型声明.过时的类型声明可能会误导您.使用类型检查器会抑制您使用大威力特性.
结论:强烈推荐您在更新代码时使用 python 类型分析.在添加或修改公共API时使用类型注释,在最终构建整个项目前使用 pytype 来进行检查.由于静态分析对于 python 来说还不够成熟,因此可能会出现一些副作用(例如错误推断的类型)可能会阻碍项目的部署.在这种情况下,建议作者添加一个 TODO 注释或者链接,来描述当前构建文件或是代码本身中使用类型注释导致的问题.
(译者注: 代码类型注释在帮助IDE或是vim等进行补全倒是很有效)
注释
确保对模块, 函数, 方法和行内注释使用正确的风格
文档字符串Python有一种独一无二的的注释方式: 使用文档字符串. 文档字符串是包, 模块, 类或函数里的第一个语句. 这些字符串可以通过对象的 __doc__
成员被自动提取, 并且被pydoc所用. (你可以在你的模块上运行pydoc试一把, 看看它长什么样). 我们对文档字符串的惯例是使用三重双引号”””( PEP-257 ). 一个文档字符串应该这样组织: 首先是一行以句号, 问号或惊叹号结尾的概述(或者该文档字符串单纯只有一行). 接着是一个空行. 接着是文档字符串剩下的部分, 它应该与文档字符串的第一行的第一个引号对齐. 下面有更多文档字符串的格式化规范.
模块每个文件应该包含一个许可样板. 根据项目使用的许可(例如, Apache 2.0, BSD, LGPL, GPL), 选择合适的样板.其开头应是对模块内容和用法的描述.
1 | """A one line summary of the module or program, terminated by a period. |
函数和方法下文所指的函数,包括函数, 方法, 以及生成器.
一个函数必须要有文档字符串, 除非它满足以下条件:
- 外部不可见
- 非常短小
- 简单明了
文档字符串应该包含函数做什么, 以及输入和输出的详细描述. 通常, 不应该描述”怎么做”, 除非是一些复杂的算法. 文档字符串应该提供足够的信息, 当别人编写代码调用该函数时, 他不需要看一行代码, 只要看文档字符串就可以了. 对于复杂的代码, 在代码旁边加注释会比使用文档字符串更有意义.
覆盖基类的子类方法应有一个类似 See base class
的简单注释来指引读者到基类方法的文档注释.若重载的子类方法和基类方法有很大不同,那么注释中应该指明这些信息.
关于函数的几个方面应该在特定的小节中进行描述记录, 这几个方面如下文所述. 每节应该以一个标题行开始. 标题行以冒号结尾. 除标题行外, 节的其他内容应被缩进2个空格.
Args:列出每个参数的名字, 并在名字后使用一个冒号和一个空格, 分隔对该参数的描述.如果描述太长超过了单行80字符,使用2或者4个空格的悬挂缩进(与文件其他部分保持一致).描述应该包括所需的类型和含义.如果一个函数接受foo(可变长度参数列表)或者bar (任意关键字参数), 应该详细列出foo和bar.
Returns: (或者 Yields: 用于生成器)描述返回值的类型和语义. 如果函数返回None, 这一部分可以省略.
Raises:列出与接口有关的所有异常.
1 | def fetch_smalltable_rows(table_handle: smalltable.Table, |
在 Args:
上进行换行也是可以的:
1 | def fetch_smalltable_rows(table_handle: smalltable.Table, |
类类应该在其定义下有一个用于描述该类的文档字符串. 如果你的类有公共属性(Attributes), 那么文档中应该有一个属性(Attributes)段. 并且应该遵守和函数参数相同的格式.
1 | class SampleClass(object): |
块注释和行注释
最需要写注释的是代码中那些技巧性的部分. 如果你在下次 代码审查 的时候必须解释一下, 那么你应该现在就给它写注释. 对于复杂的操作, 应该在其操作开始前写上若干行注释. 对于不是一目了然的代码, 应在其行尾添加注释.
1 | # We use a weighted dictionary search to find out where i is in |
为了提高可读性, 注释应该至少离开代码2个空格.
另一方面, 绝不要描述代码. 假设阅读代码的人比你更懂Python, 他只是不知道你的代码要做什么.
1 | # BAD COMMENT: Now go through the b array and make sure whenever i occurs |
全局变量
避免全局变量
定义:定义在模块级的变量.
优点:偶尔有用.
缺点:导入时可能改变模块行为, 因为导入模块时会对模块级变量赋值.
结论:避免使用全局变量.鼓励使用模块级的常量,例如 MAX_HOLY_HANDGRENADE_COUNT = 3
.注意常量命名必须全部大写,用 _
分隔.具体参见 命名规则若必须要使用全局变量,应在模块内声明全局变量,并在名称前 _
使之成为模块内部变量.外部访问必须通过模块级的公共函数.具体参见 命名规则
嵌套/局部/内部类或函数
使用内部类或者嵌套函数可以用来覆盖某些局部变量.
定义:类可以定义在方法, 函数或者类中. 函数可以定义在方法或函数中. 封闭区间中定义的变量对嵌套函数是只读的. (译者注:即内嵌函数可以读外部函数中定义的变量,但是无法改写,除非使用 nonlocal
)
优点:允许定义仅用于有效范围的工具类和函数.在装饰器中比较常用.
缺点:嵌套类或局部类的实例不能序列化(pickled). 内嵌的函数和类无法直接测试.同时内嵌函数和类会使外部函数的可读性变差.
结论:使用内部类或者内嵌函数可以忽视一些警告.但是应该避免使用内嵌函数或类,除非是想覆盖某些值.若想对模块的用户隐藏某个函数,不要采用嵌套它来隐藏,应该在需要被隐藏的方法的模块级名称加 _
前缀,这样它依然是可以被测试的.
命名
模块名写法: module_name
;包名写法: package_name
;类名: ClassName
;方法名: method_name
;异常名: ExceptionName
;函数名: function_name
;全局常量名: GLOBAL_CONSTANT_NAME
;全局变量名: global_var_name
;实例名: instance_var_name
;函数参数名: function_parameter_name
;局部变量名: local_var_name
.
函数名,变量名和文件名应该是描述性的,尽量避免缩写,特别要避免使用非项目人员不清楚难以理解的缩写,不要通过删除单词中的字母来进行缩写.
始终使用 .py
作为文件后缀名,不要用破折号.
应该避免的名称
- 单字符名称, 除了计数器和迭代器,作为
try/except
中异常声明的e
,作为with
语句中文件句柄的f
. - 包/模块名中的连字符(-)
- 双下划线开头并结尾的名称(Python保留, 例如init)
命名约定
- 所谓”内部(Internal)”表示仅模块内可用, 或者, 在类内是保护或私有的.
- 用单下划线(_)开头表示模块变量或函数是protected的(使用from module import *时不会包含).
- 用双下划线(__)开头的实例变量或方法表示类内私有.
- 将相关的类和顶级函数放在同一个模块里. 不像Java, 没必要限制一个类一个模块.
- 对类名使用大写字母开头的单词(如CapWords, 即Pascal风格), 但是模块名应该用小写加下划线的方式(如lower_with_under.py). 尽管已经有很多现存的模块使用类似于CapWords.py这样的命名, 但现在已经不鼓励这样做, 因为如果模块名碰巧和类名一致, 这会让人困扰.
循环
大小循环问题,小循环在外,大循环在内
1 | >>> import time |
VS
1 | >>> import time |
上面两种情形,同样遍历两次for循环,第一种方式无论耗时,性能都要比第二种好的多。 原因就是第二种方式,CPU要不停的切换,切换是需要耗时的,而且第二种方式从美观来说,是不如第一种。
在循环的时候,最好使用xrange来替代range
range()函数再遍历的时候会一次性列表都获取出来,xrange()会一个个获取,如果数据量小时,区别很小,如果数据量特别大时,差别会很大!
1 | import time |
VS
1 | import time |
如果for循环有条件判断,可以将条件放到for循环外
上面的这一条主要的安装Python的代码规范来说的。按照PEP8的规范无疑更推荐这种:
1 | >>> if OS_TYPE = "win32": |