pep-8
也算是用了一段时间的python了,但是想要符合python的代码规范pep-8那可是必须读的。
Indentation
缩进是python的一大特点,对于每一个段落(level)的缩进,pep-8给出的规范是4 spaces。有的编辑器默认是8 spaces的,建议修改一下。
对于那些个hanging indents应该视为一个level添加缩进。你可以这样:
#python的缩进可以让代码更readable
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
foo = long_function_name(var_one, var_two,
var_three, var_four)
foo = long_function_name(
var_one, var_two,
var_three, var_four)
但是要避免下面的写法:
#WARNING
foo = long_function_name(var_one, var_two,
var_three, var_four)
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
对于} ] )
这样的闭合符号如果跨过了多行怎么办?
你可以对齐元素的level:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
也可以对齐该结构的level:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
Tabs or Spaces?
pep-8是这么说的:
Spaces 是首选的缩进方法,Tabs只应该被用在保持用Tabs缩进的段落之间一致性上。
不管是那个,不要混合使用!
Maximum Line Length
一行最多能摆多少字符,嗯...应该是79个。如果是文档注释一类的限制则为72个字符。
你可以用\来在下一行延续你的代码,当然更欢迎使用括号来包裹你的表达式进行换行。
with open('/path/to/some/file/you/want/to/read') as file_1, \
open('/path/to/some/file/being/written', 'w') as file_2:
file_2.write(file_1.read())
当然在换行过后要确保适当的缩进。
Should a line break before or after a binary operator?
在操作符前换行或者在操作符后面换行。python的特点是readable,所以建议这样写:
# Yes: easy to match operators with operands
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
当然也不是不可以在操作符后面换行,但是要注意保持一致性。
Blank Lines
空白行怎么用?
- top-level function和class之间两空两行。
- 类内的方法的定义之间空一行。
- 在方法中使用空白行作为逻辑区分
- 其他地方尽量不要再空行。
Source File Encoding
- 尽量使用UTF-8(或者 ASCII in python2)。
- 对于使用ASCII码的python2文件或者使用UTF-8的python3文件,不要进行编码声明。
- 所有的标准库里的标识符都必须使用ASCII编码,并且在可以使用英文的时候尽量使用英文。唯一的一些例外是测试用例和你的名字。开源的项目更鼓励这样做(嗯,应该在来个中文版...)。
- 不是默认的编码只能用在测试或者注释里。
Imports
imports应该分行写,from something import ...
例外:
Yes: import os
import sys
No: import sys, os
imports应该放在文件的顶部,在模块注释和文档字符串后面,在全局变量和常量之前。
imports还应该按照如下顺序分组:
- 标准库的imports
- 第三方部分的imports
- 本地声明的imports
- 在每一类imports之间你应该空一行。
把任何有关all的说明放到imports的后面。
Absolute imports or Explicit imports
推荐完全引入,它们更可读也更可靠。
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
不过,相对引入也可用于替代绝对完全引入特别是处理复杂的包时完全引入会造成不必要的冗长。
from .import sibling
from .sibling import example
对于标准库的imports必须使用完全引入。要避免from
这样的写法,这样会带来混淆,对于包的名称要明确并且做好区分,方便管理。
Whitespace in Expressions and Statements
表达式和语句中的空格怎么用?
下面的情况应该避免多余的空格:
- 紧挨着各种括号应该这么写:
Yes: spam(ham[1], {eggs: 2})
- 后面紧跟着逗号、分号或者冒号:
Yes: if x == 4: print x, y; x, y = y, x
- 紧挨着调用函数括号:
Yes: spam(1)
- 序列的左括号后不要加空格:
Yes: dct['key'] = lst[index]
- 在任何行尾不要使用空格。
其他空格:
- 在这些个操作符的两边都使用一个空格:
assignment (=), augmented assignment (+=,-=etc.), comparisons (==,<,>,!=,<>,<=,>=,in,not in,is,is not), Booleans (and,or,not).
- 在不同优先级的操作符之间可以考虑添加空格(建议实在优先级低的一边),二元操作符两边使用相同的空格数,不要超过一个
- 切片里的冒号感觉像一个二元操作符,它的两边应该留有相同个数的空格,如果切片中有扩展冒号,使用相同的格式。当然如果冒号的参数被省略,那么空格也省略:
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
- 操作符左右各加一个空格使它们对齐(但是不要强行对齐):
x = 1
y = 2
long_variable = 3
- 在函数定义中的参数默认值和key值所使用的=号两边不要添加空格:
def complex(real, imag=0.0):
- 不鼓励使用组合语句,也就是尽量不用 ; 组合,该分行的时候就分行。
- 在
if / for / while
语句块中,该分行就分行,即使只有一行。
Comments
哈哈,这个跟hello world
基本上出现频率相同的东西又来啦——注释。
- 误导人的注释有了不如没有,所以记得更新你的注释。
- 在你的注释里不要改变表示符的写法,make it readable。并且要让你的注释是一个大写开头 句号结尾 的完整的句子。
- 在每个句子结束的时候应该用两个空格。
- 中国的朋友请用英语编写注释,除非你120%的肯定不会有老外看...
Python coders from non-English speaking countries: please write your comments in English, unless you are 120% sure that the code will never be read by people who don't speak your language.
其实我想说:
Python coders from English speaking countries: please write your comments in Chinese, unless you are 120% sure that the code will never be read by people who just speak Chinese.
好吧纯属玩笑啦。
Block Comments:块注释,用于注释跟着它的那些个代码,注释应该和备注释的代码处于同一个level,使用一个#和一个空格开始,如果要分段的话,使用只有#的空白行注释分割。
Inline Comments:行注释,再需要的时候使用,做一些适当的说明。使用一个#和一个空格。
Documentation Strings:文档字符串,你应该为每一个公共的模块,函数,类,方法写一个文档字符串,非public的函数也许不需要文档字符,但是你应该在它的def
之后给他写一个注释。在变写文档字符的时候也要保持"""的缩进。
Version Bookkeeping
版本声明,在你的source file里面添加:__version__ = "$Revision: 9afe77ad549b $"
这行代码应该紧跟在文档字符串后面。
Naming Conventions
命名规范。先来一看一看:
The naming conventions of Python's library are a bit of a mess, so we'll never get this completely consistent -- nevertheless, here are the currently recommended naming standards. New modules and packages (including third party frameworks) should be written to these standards, but where an existing library has a different style, internal consistency is preferred.
一般有这么几种命名格式:
- b(single lowercase letter)
- B(single uppercase letter)
- lowercase
- lower_case_with_underscores
- UPPERCASE
- UPPER_CASE_WITH_UNDERSCORES
- CapitalizedWords(or CapWords, or CamelCase )
Note: When using abbreviations in CapWords, capitalize all theletters of the abbreviation. Thus HTTPServerError is better thanHttpServerError. - mixedCase
(differs from CapitalizedWords by initial lowercasecharacter!) - Capitalized_Words_With_Underscores (ugly!)
python变量中的公认的下划线使用方法:
-
_single_leading_underscore
弱“内部使用”指标。用from module import *
的方式不能导入这样的对象。 -
single_trailing_underscore_
通过_
后缀避免与Python关键字的冲突,例如Tkinter.Toplevel(master, class_='ClassName')
-
__double_leading_underscore
当命名类属性的时候,使得(类foobar
内的__boo成为_foobar__boo
;这是python的名称修改机制见下文) -
__double_leading_and_trailing_underscore__
“奇妙”的对象或者属性,不要发明这样的名字,用文档里面定义好的。 - 在python中很少使用统一前缀来表示有相近关系的变量
命名规定:
- Names to Avoid:不要单独使用
l O I
这几个字母作为变量名。 - Package and Module Names:模块命名尽量短小,使用全部小写的方式,可以使用下划线。包命名尽量短小,使用全部小写的方式,不可以使用下划线。C/C++的扩展用到python的话命名使用
_modulename
的方式。 - Class Names:类的命名使用ClassName的方式,模块内部使用的类采用_ClassName的方式。
- Exception Names:异常命名使用CapWords+Error后缀的方式。
- Function Names:函数命名使用全部小写的方式,可以使用下划线。
- Global Variable Names:全局变量命名使用函数的命名方式。实现单模板的全局变量方法有两种,一是在其他模板导入时使用all机制;二是前缀一个下划线(即将变量视为模板非公开)。
- Function and method arguments:函数和方法的变量名称的命名,
self,cls
分别对应实例方法和类方法的第一个参数 。如果参数与关键字重名,在最后加一个下划线。 - Constants:常量通常定义在模块层,常量命名使用全部大写的方式,可以使用下划线。
- Method Names and Instance Variables:方法名称和实例变量的命名规则和函数的命名规则一致。还应注意:
- 如果是非公的方法或者实体在命名前面加上一个下划线。
- 为了避免子类父类命名冲突,用两个前缀下划线调用python的名称改写机制。
- 这里是原文的引用:
Use one leading underscore only for non-public methods and instance variables.
To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.
Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.
Designing for inheritance
提供面向对象的语言都涉及继承的设计,python也不例外。
在设计之初一定要决定类的方法和实例变量应该是公有的还是非公的,如果还没有决定,那就先设为非公的,因为从非公到公的转化比从公到非公的转化简单,改得时候方便。
python里省略了private,python中没有真正意义上的private变量,这样使事情变得轻松不少。
还有一种属性是作为“子类的API”存在的(其他语言称为protect的属性)。有些类生来就是要被继承的,在子类中做些扩展改变一下类的方法行为,在设计这样的类的时候,明确的决定好哪些属性是公有的,哪些是作为子类的API的,哪些是只用与基类的。
With this in mind, here are the Pythonic guidelines:
- 公有的属性名不要有前缀下划线
- 如果你的共有的属性名字与保留的关键字冲突,最好缩写一下。 (However, notwithstanding this rule, 'cls' is the preferred spelling for any variable or argument which is known to be a class, especially the first argument to a class method.)
- 对于简单的数据属性,简单明了的命名就好。
- 如果你的类要派生子类,并且你有不想让子类访问的类型,考虑将它们使用双下划线前缀并且没有后缀下划线的方式命名,这会调用python的名称改写算法。这可以帮助你避免子类不小心出现和父类同名属性而产生的问题。
- 只有单继承有这样的机制,如果一个子类选择了同名的class和同名的属性名,还是会有冲突。
- 名称改写机制会让一些工作变得不是很方便,比如调试和
__getarr()__
,然而记录和易于手动执行。 - 不是每个人都喜欢名称改写。
Public and internal interfaces
公共和内部接口。
模块应该用一个__all__
显示的声明它的公开接口,文档化的接口如果在文档内部没有说明那么它应该是一个公共接口。
内部的接口在名字前面加上_
。
__author__=='xuehao'
在下初入python,如果内容有差错,还请大家指出。
email:[email protected]