PEP8是Python官网指导推荐的编程规范,OpenStack等项目都遵循它。上元也要求严格遵循该规范。本文中附着了PEP8原文,同时附带一篇中文翻译稿。推荐使用PyChram编辑python代码,它可自动提示那些不满足编程规范的代码, PyChram已经默认导入PEP8规范。如果已经习惯用Eclipse的PyDev,可以用文中附件--pep8检测工具检测自己的代码是否符合PEP8规范。
目录
1. 代码编排 3
1.1. 缩进 3
1.2. 每行最大长度79 4
1.3. 空行规则 5
1.4. 编码方式 5
1.5. Import 5
2. 空格的使用 6
2.1. 各种右括号前不要加空格 6
2.2. 逗号、冒号、分号前不要加空格,在他们后面加 7
2.3. 参数列表, 索引或切片的左括号前不应加空格 7
2.4. 在二元操作符两边都加上一个空格 7
2.5. 在算术运算符前后加空格 7
2.6. 不要在一个关键字参数或者一个缺省参数值的 = 符号前后加一个空格 8
2.7. 通常不推荐使用复合语句(一行代码中有多条语句) 8
2.8. 通常情况下,一行代码包括一个小的if/for/while块,是可以的。但是多子句绝不可以。同样,需要避免折叠类似的长代码行! 8
3. 注释 9
3.1. 块注释 9
3.2. 行注释 9
3.3. 文档描述 9
4. 命名规范 10
4.1. 命名风格 10
4.2. 避免使用的名字 11
4.3. 包和模块名称 11
4.4. 类名 12
4.5. Exception名 12
4.6. 全局变量名 12
4.7. 函数(Function)名 12
4.8. 函数(Function)和方法(Method)参数 12
4.9. 方法(Method)名和实例变量 13
4.10. 常量 13
4.11. 继承设计 13
5. 编码建议 14
6. 上元特殊规定 17
7. Python代码总体结构 18
8. 原文(英文版) 19
9. 检测工具 20
9.1. PyCharm中自带PEP8的检测,点击右边匡的黄色字体即可看到提示 20
9.2. 用pep8工具检测 20
9.3. 用pylint工具检测 20
4个空格的缩进(编辑器都可以完成此功能),不使用Tap,更不能混合使用Tap和空格。
以下是带括号的一些缩进原则。
Yes:
#和括号开始的部分对齐
foo = long_function_name(var_one, var_two,
var_three, var_four)
No:
# 禁止对齐下一层的代码
foo = long_function_name(var_one, var_two,
var_three, var_four)
No:
# 需要进一层的缩进,区分下一层的代码
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
如果if语句占用多行,推荐不需要特殊的缩进
#不需要特殊的缩进
if (this
and that):
do_something()
在闭合的括号中,后面的括号对齐变量名:
my_list = [
1, 2, 3,
4, 5, 6,
]
result = some_function_that_takes_arguments(
'a', 'b', 'c',
'd', 'e', 'f',
)
换行可以使用反斜杠,最好使用圆括号。换行点要在操作符的后边敲回车。
较长代码行折行的首选方法是在圆括号、方括号和花括号内使用Python的隐式续行方式。通过圆括号内的表达式的折行来把较长的代码行折成多行。同时确保适当的续行缩进。二元运算符的首选的折行处是在运算符之后,而不是之前。
class Rectangle(Blob):
def __init__(self, width, height,
color='black', emphasis=None, highlight=0):
if (width == 0 and height == 0 and
color == 'red' and emphasis == 'strong' or
highlight > 100):
raise ValueError("sorry, you lose")
if width == 0 and height == 0 and (color == 'red' or
emphasis is None):
raise ValueError("I don't think so -- values are %s, %s" %
(width, height))
Blob.__init__(self, width, height,
color, emphasis, highlight)
类和顶层函数定义之间空两行;
类中的方法定义之间空一行;
函数内逻辑无关段落之间空一行;
其他地方尽量不要再空行。
import xxx
class Rectangle(Blob):
def __init__(self, width, height,
color='black', emphasis=None, highlight=0):
... ...
def abc(self):
... ...
Python文件必须使用UTF-8格式。IDE文件编码方式设置成UTF-8。
python文件第一行写上,这样才能写中文注释
# -*- coding: utf-8 -*-
在代码中的字符串应该使用\x, \u, \U或者\N来包含非ASCII数据。
Yes:
import os
import sys
No:
import sys, os
按标准、第三方,上元外部模块,上元内部模块顺序依次排放,之间空一行。
import sys
Import os
from twisted.application import service
from ozcommon import configruration
Yes:
import mypkg.sibling
from mypkg import sibling
from mypkg.sibling import example
No:
from .import sibling
from .sibling import example
总体原则,避免不必要的空格。
Yes:
spam(ham[1], {eggs: 2}, [])
No:
spam( ham[ 1 ], { eggs: 2 }, [ ] )
Yes
if x == 4:
print x, y
x, y = y, x
No
if x == 4 :
print x , y
x , y = y , x
Yes
spam(1)
dict['key'] = list[index]
No
spam (1)
dict ['key'] = list [index]
Yes
x == 1
y = 1
No
x<1
x = 1
y = 2
long_variable = 3
Yes:
i = i + 1
submitted += 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
No:
i=i+1
submitted +=1
x = x * 2 - 1
hypot2 = x * x + y * y
c = (a + b) * (a - b)
Yes:
def complex(real, imag=0.0):
return magic(r=real, i=imag)
No:
def complex(real, imag = 0.0):
return magic(r = real, i = imag)
Yes:
if foo == 'blah':
do_blah_thing()
do_one()
do_two()
do_three()
No:
if foo == 'blah': do_blah_thing()
do_one(); do_two(); do_three()
No:
if foo == 'blah': do_blah_thing()
else: do_non_blah_thing()
try: something()
finally: cleanup()
do_one(); do_two(); do_three(long, argument,
list, like, this)
if foo == 'blah': one(); two(); three()
不好理解的注释不如没有注释。注释要和代码保持与时俱进!注释应该是一条完整的句子。代码注释请用中文,除非语法特殊字符或者变量名等。
在一段代码前增加的注释。在‘#’后加一空格。段落之间以只有‘#’的行间隔。比如:
# 这是块注释段落1
#
# 这是块注释段落2
#
# 这是块注释段落3
在一句代码后加注释。
如果语句显而易见,那么内嵌注释是不必要的,比如:
x = x + 1 # x加1
而应该是有意义的注释。格式要求:语句后面要加2个空格,在加#号,之后再加一个空格,之后再写注释。
x = x + 1 # 边界弥补
避免无谓的注释
为所有的共有模块、函数、类、方法写文档描述;非共有的没有必要,但是可以写注释(在def的下一行)。
注意最重要的是,""" 作为多行的文档字符串的结束,应该单独一行,并且之前有一个空行
"""返回卷对象
该卷对象为你输入src_vol卷的克隆
"""
有如下命名规范:
lowercase 全小写字母
lower_case_with_underscores 使用下划线分隔的小写字母
UPPERCASE 大写字母
UPPER_CASE_WITH_UNDERSCORES 使用下划线分隔的大写字母
CapitalizedWords 多个单词无分隔符连接,每个单词首字母大写。大驼峰命名法。
名称前后下划线有特殊意义:
单下划线开始指弱"内部使用"。例如:from M import * 不会导入以下划线开始的对象。
_single_leading_underscore
单下划线结束用来避免与Python关键字冲突
Tkinter.Toplevel(master, class_='ClassName')
双下划线开始,该方法不会被子类继承。
class A(object):
def __init__(self):
self.__private()
self.public()
def __private(self):
print 'A.__private()'
def public(self):
print 'A.public()'
class B(A):
def __private(self):
print 'B.__private()'
def public(self):
print 'B.public()'
b = B()
上述代码正确的答案是:
A.__private()
B.public()
永远不要使用‘l’(小写的L),‘O’(大写的o)和I(大写的i)作为单字变量名。
在某些字体中,这些字很难和数字的0 和 1 区分。当打算用'l'的时候,用'L'来代替。
模块应该用简短的,全小写的名字。如果能增强可读性的话,可以使用下划线。 Python的包也要用全小写的,短名称,但是不建议用下划线。
因为模块名称和文件名关联,而且某些文件系统大小写不敏感,也会截断过长的名字。所以模块选用相当简短的名字是很重要的。 在Unix下不会有这样的问题,但是在早些的Mac、Windows 或者 DOS下会有这样的问题。
当用C或C++连编写一个含有Python模块提供更高层(比如,更加面向对象)接口的扩展模块时,这个C/C++模块要有一个前导下划线(例如 _socket)
类名要用首字母大写的规则。内部类,要加上前导下划线。
class SiteController(object):
Class __InnerInstance(object):
def __init__(self, a, b):
... ...
def __init__(self):
self.obj = __InnerInstance(1, 2)
Exception也是类,所以这里也用类名规则。一般产生了明显错误的异常定义后缀为Error的异常
class APIException(Exception):
def __init__(self):
... ...
class IOError(Exception):
... ...
这些规则和函数规则一样。
被设计为通过from M import *导入的模块。应该用__all__机制来防止导出全局。或者使用过去的全局变量前置下划线的规则(这是为了说明这些变量是"模块私有的")。
函数名应该用小写,为了增加可读性可以用下划线分隔
def add_instance(arg1, arg2):
... ...
def del_instance(arg1, arg2):
... ...
始终用self作为实例方法的第一个参数。
始终用cls作为类方法的第一个参数。
如果函数的参数名和保留字冲突。用结尾下划线比缩写或是滥用的组词更好。因此 class_ 比 clss好。(也许,更好的避免冲突的方式是用同义词。)
class A(object):
#类实例方法
def foo(self, x):
print "executing foo(%s, %s)" % (self, x)
#类方法
@classmethod
def class_foo(cls, x):
print "executing class_foo(%s, %s)" % (cls, x)
def fun1(self, class_=None):
... ...
使用函数命名规则:使用下划线分隔的小写字母会提高可读性。
只在私有方法和实例变量前使用单下划线。
class A(object):
# 共用方法
def fun_foo(self, x):
... ...
# 私有方法
def _fun2(self):
... ...
使用前导双下划线调用Python的名字变化规则来避免与子类中的名字冲突。
常量通常在模块级别中定义,用全大写和下划线分隔的字符来编写。例如
MAX_OVERFLOW
TOTAL
考虑一个类的方法或实例变量(总体而言:属性)应该是公用的或者非公用的。如果不能确定的话,设计为私有的。
公有属性,是你希望第三方使用的,并通过你的委托机制来避免由于属性变更导致的向后不兼容。 私有属性,是你不希望被第三方使用的。你不能保证私有属性不会改变甚至被删除。
贯穿着这样的思想,如下是Python的准则:
l 公有属性不应该用下划线开始
class A(object):
public_variable = 0
def public_fun(self):
print 'A.public()'
l 对于单一的公有数据属性,最好是直接用其属性名,而非复杂的存取器/突变期方法。
l 如果你的类打算用来继承的话,并且你的属性不希望子类继承,那么考虑用双下划线开头,不要有结尾下划线
class A(object):
def __init__(self):
self.__private()
self.public()
def __private(self):
print 'A.__private()'
def public(self):
print 'A.public()'
class B(A):
def __private(self):
print 'B.__private()'
def public(self):
print 'B.public()'
b = B()
上述代码正确的答案是:
A.__private()
B.B.public()
代码应该用不损害其他Python实现的方式去编写(PyPy, Jython, IronPython, Cython, Psyco 等) 例如,不要依赖于CPython的高效内置字符连接语句a += b or a = a + b.这些语句在Jython中运行较慢。在性能敏感的库中,应该用''.join() 来取代。这样可以保证在不同的实现中,字符链接花费的时间都呈线性。
l 与诸如None这样的字符比较时,要使用is or is not,永远不要用等于操作。同样地,在测试一个变量或参数默认值为None被设置为其他值时(比如if x表示if x is not None时),要注意。 这个值应该有一个能在布尔逻辑的上下文中为false的类型(比如容器)。
l 使用is not 操作符要比not ... Is好。虽然他们表达的意思相同,但是前一个更好理解:
Yes:
if foo is not None:
No:
if not foo is None:
l 当用复杂比较实现排序操作时,最好去实现全部六个操作(__eq__, __ne__, __lt__, __le__, __gt__, __ge__),而不是依靠其他的代码去实现一些怪异的比较。
l 使用基于对象的异常。模块或者包应该定义自己的异常基类,这个类应该继承自内置的Exception类。总要包含类文档语句,例如:
class MessageError(Exception):
"""Base class for errors in the email package."""
在这里用到类命名规范。
l 当抛出一个异常的时候,使用raise ValueError('message')代替旧的raise ValueError, 'message'格式。推荐使用这种括弧的格式,当异常的参数很长或者是格式化字符串的时候,由于括号的关系,我们不需要使用连字符。旧的格式在Python 3 中被移除。
l 当捕获一个异常的时候,要用详细异常声明代替光秃秃的except: 语句.
例如:
try:
import platform_specific_module
except ImportError:
platform_specific_module = None
一个空的except:语句将会捕获 SystemExit 和 KeyboardInterrrupt 异常。这会使得很难用Control-C来中断一个程序,并且还会隐藏其他的问题。
如果你想捕获一个程序中的所有异常,使用except Exception。
l try里的东西要单纯,不要引入不可预见的其他异常被你的except捕获:
Yes:
try:
value = collection[key]
except KeyError:
return key_not_found(key)
else:
return handle_value(value)
No:
try:
return handle_value(collection[key])
except KeyError:
# handle_value函数内的KeyError 异常也会被捕获
return key_not_found(key)
l 使用String方法而非String模块。String方法更加快捷并且使用和unicode字符一样的API。如果需要向后兼容2.0之前的版本的话,可以不考虑这条规则。
Yes:
str = ‘abc’
str.upper()
No:
str = ‘abc’
import string
string.upper(s)
l 使用''.startswith() 和 ''.endswith()而非字符切片去检测前缀或后缀。
startswith() and endswith() 更加绿色,错误更少。例如:
Yes:
if foo.startswith('bar'):
No:
if foo[:3] == 'bar':
l 对象类型比较总要用 isinstance() 而非直接比较
Yes:
if isinstance(obj, int):
No:
if type(obj) is type(1):
当检测一个对象是否是字符串是,记住,它可能是unicode字符。在Python 2.3, str和unicode有同样的基类——basestring, 那么你可以这样做:
if isinstance(obj, basestring):
l 对于序列,(strings, lists, tuples),利用空序列为false这一点。
Yes:
if not seq:
if seq:
No:
if len(seq)
if not len(seq)
l 书写字面值时不要依靠后面的空格。这些后面的空格,视觉上难以区分,而且很多编辑器(或者,眼前的,reindent.py)会去掉他们。
l 别用‘==’进行布尔值和 True 或者 False 的比较
Yes:
if greeting:
No:
if greeting == True:
Worse:
if greeting is True:
l 总是使用def语句而不是一个lambda表达式赋值给一个变量
例如:
Yes:
def f(x): return 2*x
No:
f = lambda x: 2*x
1. IDE必须使用PyCharm
2. 一个函数长度不能超过100行,推荐在一个屏幕内
3. 不需要的代码一定删除,包括没有使用的import语句
4. 注释,log里不能出现名字等个人信息
5. 能找到公用代码的地方尽量用公用代代码,并主动把公用代码描述清楚
6. 关于配置文件
主要是/usr/share/sunyacloud/config-templates/xxx.ini.tmpl和每个服务下的config.spec
类型用[]标识,分级用[]的前套数表示,比如[[]]
等号前后有空格
[]前后,里面没有空格
[shapes]
[[__many__]]
ram = integer
cpus = float
7. 权限检查,log处理等通用函数建议用装饰器封装
8. 把注释中所有含有decompile文字都去掉。例如:# --== Decompile ==--
9. 把python代码中所有开始部分的#yes注释都去掉。
10. 建议在每个python文件的开头都使用我们公司代码的License和copyright说明文字。这样比较专业
# Copyright (c) 2011 sunya
# All Rights Reserved.
#
# Licensed under the sunya License, Version 1.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.sunya.com/licenses/LICENSE-1.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
11. 禁止把一个非常复杂的字典变量,传递到很多方法中,让别人很难猜测字典中包含哪些内容;建议改成使用类对象传递
本文英文出处: http://www.python.org/dev/peps/pep-0008/
方法:1)解压附件
2)执行“python pep8.py --you want to check file--”。例如:
1) 执行pylint
2) 结果如下:
工具下载地址: http://pylint.org