跳到主要内容 Python 编码风格与规范 | 极客日志
Python
Python 编码风格与规范 基于 PEP8 整理了 Python 编码规范与风格,涵盖缩进、行长度、空白符、操作符、括号、空行、编码、Shebang、模块引用、魔术变量、注释、文档字符串、类型提示、字符串、文件与 Socket、访问控制、Main 入口及命名规则。同时介绍了三目运算符、None 判断、Lambda、异常处理、条件表达式、布尔运算、列表推导式、函数及变量等编码规范,并推荐了 flake8、pylint、black 和 EditorConfig 等工具进行代码检查与格式化。
灵魂伴侣 发布于 2026/3/24 更新于 2026/4/17 1.5K 浏览Python 编码风格与规范
前言:为了让不同编码习惯的开发者更好的协作配合,并且形成良好的基础编码规范与风格,我们以 PEP8 为基础,修改了陈旧的规则,丰富了示例,并整理了工作中常见的不规范操作,最终形成此 Python 编码规范与风格。
一、编码风格
规范地代码布局有助于帮助开发者更容易地理解业务逻辑。
1.1 缩进
1.1.1【必须】
对于每级缩进,统一要求使用 4 个空格,而非 tab 键。pylint:bad-indentation.
1.1.2【必须】
续行,要求使用括号等定限界符,并且需要垂直对齐。
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)
foo = long_function_name(
var_one, var_two, var_three, var_four)
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)
1.1.3【推荐】 如果包含定界符(括号,中括号,大括号)的表达式跨越多行,那么定界符的扩回符,可以放置与最后一行的非空字符对齐或者与构造多行的开始第一个字符对齐。
my_list = [
1 , 2 , 3 , 4 , 5 , 6 ,
]
result = some_function_that_takes_arguments(
'a' , 'b' , 'c' , 'd' , 'e' , 'f' ,
)
my_list = [
1 , 2 , 3 , 4 , 5 , 6 ,
]
result = some_function_that_takes_arguments(
'a' , 'b' , 'c' , 'd' , 'e' , 'f' ,
)
1.1.4【推荐】 对于会经常改动的函数参数、列表、字典定义,建议每行一个元素,并且每行增加一个 ,。
yes = ('y' , 'Y' , 'yes' , 'TRUE' , 'True' , 'true' , 'On' , 'on' , '1' )
kwlist = [
'False' , 'None' , 'True' , 'and' , 'as' , 'assert' ,
...
'yield' ,
]
person = {
'name' : 'bob' ,
'age' : 12 ,
}
kwlist = ['False' , 'None' , 'True' , 'and' , 'as' , 'assert' , 'async' , ...]
person = {'name' : 'bob' , 'age' : 12 }
1.1.5【可选】 对于 if 判断,一般来说尽量不要放置过多的判断条件。换行时增加 4 个额外的空格。pycodestyle:E129 visually indented line with same indent as next logical line.
备注:PEP8 没有明确规定,以下几种都是允许的。建议使用前面 2 种方法,后 2 种会与已有的开源工具冲突。
if (this_is_one_thing and that_is_another_thing):
do_something()
if (this_is_one_thing and that_is_another_thing):
do_something()
if (this_is_one_thing and that_is_another_thing):
do_something()
if (this_is_one_thing and that_is_another_thing):
do_something()
1.2 每行最大长度
1.2.1【必须】 每行最多不超过 120 个字符。每行代码最大长度限制的根本原因是过长的行会导致阅读障碍,使得缩进失效。pylint:line-too-long.
x = ('This will build a very long long '
'long long long long long long string' )
1.3 空白符
1.3.1【必须】
1.3.2【必须】 禁止行尾空白。pylint:trailing-whitespace.
行尾空白虽然不会造成功能性异常,但是这些空白字符会被源码管理系统标记出来显示为差异,对开发人员造成困恼。
1.4 操作符
1.4.1【推荐】 Python 没有三目操作符,对于二目操作符来说,操作符允许在换行符之后出现。
income = (
gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest
)
income = (
gross_wages + taxable_interest + (dividends - qualified_dividends) - ira_deduction - student_loan_interest
)
1.5 括号
1.5.1【必须】 tuple 元组不允许逗号结尾,显式增加括号规避。即使一个元素也加上括号。pylint:trailing-comma-tuple.
行尾的逗号可能导致本来要定义一个简单变量,结果变成 tuple 变量。
trailingcomma = (['f' ],)
return (1 ,)
trailingcomma = ['f' ],
return 1 ,
1.6 空行
1.6.1【必须】 模块中的一级函数和类定义之间,需要 空两行。pycodestyle:E302 expected 2 blank lines.
1.6.2【必须】 类中函数定义之间,空一行。pycodestyle:E302 expected 1 blank line.
1.6.3【必须】 源文件须使用且仅使用 一个换行符 作为结尾。pylint:missing-final-newline, trailing-newlines.
1.6.4【必须】 通常每个语句应该独占一行。pylint:multiple-statements.
如果测试结果与测试语句在一行放得下,你也可以将它们放在同一行。如果是 if 语句,只有在没有 else 时才能这样做。特别地,绝不要对 try/except 这样做,因为 try 和 except 不能放在同一行。
if foo:
bar(foo)
else :
baz(foo)
try :
bar(foo)
except ValueError:
baz(foo)
if foo: bar(foo) else : baz(foo)
try : bar(foo) except ValueError: baz(foo)
try : bar(foo) except ValueError: baz(foo)
1.6.5【推荐】 """This is the example module. This module does stuff."""
import os
def foo ():
pass
class MyClass ():
def __init__ (self ):
pass
def foo (self ):
pass
class AnotherClass (object ):
"""Another class. This is some comments for another class"""
def __init__ (self, a, b ):
if a > b:
self ._min = b
self ._max = a
else :
self ._min = a
self ._max = b
self ._gap = self ._max = self ._min
def foo (self ):
pass
1.7 源文件编码
1.7.1【必须】 源文件编码需统一使用 UTF-8 编码,以下内容需要增加到每一个 python 文件的头部。
1.7.2【必须】 避免不同操作系统对文件换行处理的方式不同,一律使用 LF。pylint:mixed-line-endings, unexpected-line-ending-format.
1.8 Shebang
1.8.1【必须】 程序的 main 文件应该以 #!/usr/bin/env python2 或者 #!/usr/bin/env python3 开始,可以同时支持 Python2、Python3 的 #!/usr/bin/env python。
1.9 模块引用 (import)
1.9.1【必须】 每个导入应该独占一行。pylint:multiple-imports.
1.9.2【必须】 导入总应该放在文件顶部,位于模块注释和文档字符串之后,模块全局变量和常量之前。pylint:wrong-import-order.
导入应该按照从最通用到最不通用的顺序分组,每个分组之间,需要空一行:
每种分组中,建议每个模块的完整包路径按 字典序 排序,并忽略大小写。
import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar
1.9.3【必须】 避免使用 from <module> import *,因为可能会造成命名空间的污染。pylint:wildcard-import.
1.9.4【必须】 禁止导入了模块却不使用它。pylint:unused-import.
import os
dir_path = os.path.abspath('.' )
1.10 模块中的魔术变量 (dunders)
1.10.1【必须】 对于两个 _ 开头和两个 _ 结尾的变量,如 __all__,__author__,__version__ 等,应该放在模块文档之后,其他模块导入之前(__future__ 除外)。
1.10.2【必须】 Python 要求 future 导入必须出现在其他模块导入之前。pylint:misplaced-future.
"""This is the example module. This module does stuff."""
from __future__ import barry_as_FLUFL
__all__ = ['a' , 'b' , 'c' ]
__version__ = '0.1'
__author__ = 'Cardinal Biggles'
import os
import sys
1.11 注释
有效的注释有助于帮助开发者更快地理解代码,模块,函数,方法,以及行内注释的都有各自的风格。
1.11.1【必须】 所有 # 开头的注释,必须与所在的代码块同级,并置放在代码之上。pycodestyle:E262 inline comment should start with '# '.
1.11.2【必须】 注释的每一行都应该以 # 和一个空格开头。pycodestyle:E266 too many leading '#' for block comment, E262 inline comment should start with '# '.
1.11.3【必须】 行内注释 # 与代码离开至少 2 个空格。pycodestyle:E261 at least two spaces before inline comment.
1.11.4【必须】 块注释:对于复杂的操作,可以在代码之前写若干行注释,对简单的代码,可以放在行内。与代码离开至少 2 个空格。
if i & (i-1 ) == 0 :
...
x = x + 1
1.11.5【必须】 TODO 注释应该在所有开头处包含 TODO 字符串,紧跟着是用括号括起来的你的名字,email 地址或其它标识符,然后是一个可选的冒号。接着必须有一行注释,解释要做什么。主要目的是为了有一个统一的 TODO 格式,这样添加注释的人就可以搜索到 (并可以按需提供更多细节)。写了 TODO 注释并不保证写的人会亲自解决问题。当你写了一个 TODO,请注上你的名字。
为临时代码使用 TODO 注释,它是一种短期解决方案。常见的 IDE 在提交代码时,会检查变更中包含了 TODO 并提醒开发者,防止提交是忘记还有未完成的代码。如果 TODO 是 将来做某事 的形式,那么请确保包含一个指定的日期或者一个特定的事件(条件)。相同地,也可以留下 FIXME, NOTES 注释。
1.12 文档字符串 Docstring 文档字符串提供了将文档与 Python 模块,函数,类和方法相关联的便捷方法。
def foobar ():
"""Return a foobang Optional plotz says to frobnicate the bizbaz first."""
1.12.1【推荐】 需对外发布的 public 模块,函数,类,方法等需要包含文档字符串。内部使用的方法,函数等,要求使用简单的注释描述功能。pylint:missing-module-docstring, missing-class-docstring, missing-function-docstring.
一个函数或方法,如果可以直接被其他开发者使用,需要提供文档明确其含义,需要指出输入,输出,以及异常内容。
1.12.2【必须】
1.12.3【推荐】 def fetch_bigtable_rows (big_table, keys, other_silly_variable=None ):
"""Fetches rows from a Bigtable.
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.
:param big_table: An open Bigtable Table instance.
:param keys: A sequence of strings representing the key of each table row to fetch.
:param other_silly_variable: Another optional variable, that has a much longer name than the other args, and which does nothing.
:return: 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 ValueError: if `keys` is empty.
:raises IOError: An error occurred accessing the bigtable.Table object.
"""
pass
1.12.4【推荐】 类应该在其定义下有一个用于描述该类的文档字符串。如果类有公共属性 (Attributes),那么文档中应该有一个属性 (Attributes) 段,并且应该遵守和函数参数相同的格式。
class SampleClass (object ):
"""Summary of class here. Longer class information.... Longer class information....
:ivar likes_spam: A boolean indicating if we like SPAM or not.
:ivar eggs: An integer count of the eggs we have laid.
"""
def __init__ (self, likes_spam=False ):
"""Inits SampleClass with blah."""
self .likes_spam = likes_spam
self .eggs = 0
def public_method (self ):
"""Performs operation blah."""
1.13 类型提示 Python 是动态语言,在运行时无需指定变量类型。虽然运行时不会执行函数与变量类型注解,但类型提示有助于阅读代码、重构、静态代码检查与 IDE 的语法提示。推荐在项目中使用该特性。更多使用可以参考 类型标注支持 。
from typing import List
class Container (object ):
def __init__ (self ) -> None :
self .elements: List [int ] = []
def append (self, element: int ) -> None :
self .elements.append(element)
def greeting (name: str ) -> str :
return 'Hello ' + name
lang: str = 'zh'
success_code: int = 0
1.13.1【必须】 模块级变量,类和实例变量以及局部变量的注释应在冒号后面有一个空格。pycodestyle:E231 missing whitespace after ':'.
1.13.2【必须】
1.13.3【必须】 如果有赋值符,则等号在两边应恰好有一个空格。pycodestyle:E225 missing whitespace around operator.
code: int = 10
class Point (object ):
coords: Tuple [int , int ] = (0 , 0 )
label: str = '<unknown>'
def broadcast (servers: Sequence [Server], message: str = 'spaces around equality sign' ) -> None :
pass
code:int
code : int
class Test (object ):
result: int =0
1.13.4【推荐】 当使用类型提示出现循环引用时,可以在导入的头部使用 if typing.TYPE_CHECKING,且对类型注解使用 双引号 或 单引号 进行修饰。
import typing
if typing.TYPE_CHECKING:
from typing import Any , Dict , List , Sequence
from sphinx.application import Sphinx
class Parser (docutils.parsers.Parser):
def set_application (self, app: "Sphinx" ) -> None :
pass
1.14 字符串
1.14.1【推荐】 即使参数都是字符串,也要使用 % 操作符或者格式化方法格式化字符串。不过也不能一概而论,你需要在 + 和 % 之间权衡。
x = f'name: {name} ; score: {n} '
x = 'name: {name}; score: {n}' .format (name=name, n=n)
x = 'name: {name}; score: {n}' .format (**{"name" : name, "n" : n})
x = 'name: %(name)s; score: %(n)d' % {"name" : name, "n" : n}
x = '%s, %s!' % (imperative, expletive)
x = '{}, {}!' .format (imperative, expletive)
x = 'name: %s; score: %d' % (name, n)
x = 'name: {}; score: {}' .format (name, n)
x = '%s%s' % (a, b)
x = '{}{}' .format (a, b)
x = imperative + ', ' + expletive + '!'
x = 'name: ' + name + '; score: ' + str (n)
1.14.2【推荐】 避免在循环中用 + 和 += 操作符来累加字符串。由于字符串是不可变的,这样做会创建不必要的临时对象,并且导致二次方而不是线性的运行时间。作为替代方案,你可以将每个子串加入列表,然后在循环结束后用 .join 连接列表。(也可以将每个子串写入一个 io.StringIO 缓存中。) pylint:consider-using-join.
items = ['<table>' ]
for last_name, first_name in employee_list:
items.append('<tr><td>%s, %s</td></tr>' % (last_name, first_name))
items.append('</table>' )
html_content = '' .join(items)
employee_table = '<table>'
for last_name, first_name in employee_list:
employee_table += '<tr><td>%s, %s</td></tr>' % (last_name, first_name)
employee_table += '</table>'
1.14.3【推荐】 在同一个文件中,保持使用字符串引号的一致性。使用单引号 ' 或者双引号 " 引用字符串,并在同一文件中一直沿用这种风格。当字符串中包含单引号或者双引号时,为提高可读性,使用另外一种引号,代替转义字符。
Python('Why are you hiding your eyes?' )
Gollum("I'm scared of lint errors." )
Narrator('"Good!" thought a happy Python reviewer.' )
Python("Why are you hiding your eyes?" )
Gollum('The lint. It burns. It burns us.' )
Gollum("Always the great lint. Watching. Watching." )
1.14.4【必须】 如果要引用的字符串为多行时,需要使用双引号引用字符串。
1.14.5【必须】 文档字符串(docstring)必须使用三重双引号 """。
1.14.6【可选】 避免在代码中使用三重引号 """,因为当使用三重引号时,缩进方式与其他部分不一致,容易引起误导。
print ("This is much nicer.\n"
"Do it this way.\n" )
print ("""This is pretty ugly. Don't do this. """ )
1.14.7【推荐】 检查前缀和后缀时,使用 .startswith() 和 .endswith() 代替字符串切片。
if foo.startswith('bar' ):
1.15 文件和 sockets
1.15.1【必须】 除文件外,sockets 或其他类似文件的对象在没有必要的情况下打开,会有许多副作用,例如:
它们可能会消耗有限的系统资源,如文件描述符。如果这些资源在使用后没有及时归还系统,那么用于处理这些对象的代码会将资源消耗殆尽。
持有文件将会阻止对于文件的其他诸如移动、删除之类的操作。
仅仅是从逻辑上关闭文件和 sockets,那么它们仍然可能会被其共享的程序在无意中进行读或者写操作。只有当它们真正被关闭后,对于它们尝试进行读或者写操作将会抛出异常,并使得问题快速显现出来。
而且,幻想当文件对象析构时,文件和 sockets 会自动关闭,试图将文件对象的生命周期和文件的状态绑定在一起的想法,都是不现实的。因为有如下原因:
没有任何方法可以确保运行环境会真正的执行文件的析构。不同的 Python 实现采用不同的内存管理技术,比如延时垃圾处理机制。延时垃圾处理机制可能会导致对象生命周期被任意无限制的延长。
对于文件意外的引用,会导致对于文件的持有时间超出预期 (比如对于异常的跟踪,包含有全局变量等)。
1.15.2【推荐】 with open ("hello.txt" ) as hello_file:
for line in hello_file:
print (line)
对于不支持使用 with 语句的类似文件的对象,使用 contextlib.closing():
import contextlib
with contextlib.closing(urllib.urlopen("http://www.python.org/" )) as front_page:
for line in front_page:
print (line)
Legacy AppEngine 中 Python 2.5 的代码如使用 with 语句,需要添加 from __future__ import with_statement.
1.16 访问控制
在 Python 中,对于琐碎又不太重要的访问函数,应该直接使用公有变量来取代它们,这样可以避免额外的函数调用开销。当添加更多功能时,也可以用属性 (property) 来保持语法的一致性。
1.16.1【推荐】 如果访问属性后需要复杂的逻辑处理,或者变量的访问开销很显著,那么应该使用像 get_foo() 和 set_foo() 这样的函数调用。如果之前的代码行为已经通过属性 (property) 访问,那么就不要将新的访问函数与属性绑定。否则,任何试图通过老方法访问变量的代码就没法运行,使用者也就会意识到复杂性发生了变化。(如果可以重构这个代码是最好的了)
1.17 Main
即使是一个打算被用作脚本的文件,也应该是可导入的。并且简单的导入不应该导致这个脚本的主功能 (main functionality) 被执行,这是一种副作用。主功能应该放在一个 main () 函数中。
1.17.1【必须】 所有的文件都应该可以被导入。对不需要作为程序入口地方添加 if __name__ == '__main__'。
在 Python 中,pydoc 以及单元测试要求模块必须是可导入的。你的代码应该在执行主程序前总是检查 if __name__ == '__main__',这样当模块被导入时主程序就不会被执行。所有的顶级代码在模块导入时都会被执行。要小心不要去调用函数,创建对象,或者执行那些不应该在使用 pydoc 时执行的操作。
def main ():
...
if __name__ == '__main__' :
main()
1.18 命名
module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_VAR_NAME, instance_var_name, function_parameter_name, local_var_name.
单字符名称,除了计数器和迭代器。
包 / 模块名中的连字符 (-)。
双下划线开头并结尾的名称 (Python 保留,例如 __init__)。
1.18.1【推荐】 命名约定规则如下:pylint:invalid-name.
所谓 内部 (Internal) 表示仅模块内可用,或者,在类内是保护或私有的。
用单下划线 (_) 开头表示模块变量或函数是 protected 的 (使用 from module import * 时不会包含)。
用双下划线 (__) 开头的实例变量或方法表示类内私有。
将相关的类和顶级函数放在同一个模块里。不像 Java,没必要限制一个类一个模块。
对类名使用大写字母开头的单词 (如 CapWords, 即 Pascal 风格),但是模块名应该用小写加下划线的方式 (如 lower_with_under.py)。尽管已经有很多现存的模块使用类似于 CapWords.py 这样的命名,但现在已经不鼓励这样做,因为如果模块名碰巧和类名一致,这会让人困扰。
Type Public Internal Modules lower_with_under _lower_with_under Packages lower_with_under Classes CapWords _CapWords Exceptions CapWords Functions lower_with_under() _lower_with_under() Global/Class Constants CAPS_WITH_UNDER _CAPS_WITH_UNDER Global/Class Variables lower_with_under _lower_with_under Instance Variables lower_with_under _lower_with_under (protected) or __lower_with_under (private) Method Names lower_with_under() _lower_with_under() (protected) or __lower_with_under() (private) Function/Method Parameters lower_with_under Local Variables lower_with_under
二、编码规范
2.1 三目运算符
2.1.1【必须】 三目操作符判断,python 不支持三目运算符,但可使用如下方式,禁止使用复杂难懂的逻辑判断。
2.2 None 条件的判断
2.2.1【必须】 为提升可读性,在判断条件中应使用 is not,而不使用 not ... is。pycodestyle:E714 test for object identity should be 'is not'.
2.3 lambda 匿名函数
2.3.1【必须】 使用 def 定义简短函数而不是使用 lambda。pycodestyle:E731 do not assign a lambda expression, use a def.
使用 def 的方式有助于在 trackbacks 中打印有效的类型信息,明确使用 f 函数而不是一个 lambda 的调用。
2.4 异常
2.4.1【必须】 异常类继承自 Exception,而不是 BaseException。
2.4.2【必须】 使用新版本抛出异常的方式,禁止使用废弃的方式。pycodestyle:W602 deprecated form of raising exception.
raise ValueError('message' )
raise ValueError, 'message'
2.4.3【必须】 捕获异常时,需要指明具体异常,而不是捕获所有异常。除非已经在当前线程的最外层(记得还是要打印一条 traceback)。pylint:broad-except, bare-except.
try :
import platform_specific_module
except ImportError:
platform_specific_module = None
try :
do_something()
except Exception as ex:
log.exception(ex)
handle_exception_or_not()
try :
import platform_specific_module
except Exception:
platform_specific_module = None
try :
do_something()
except Exception:
pass
2.4.4【推荐】 def write_data ():
if check_file_exist():
do_something()
else :
raise FileNotExist()
def write_data ():
if check_file_exist():
do_something()
return 0
else :
return FILE_NOT_EXIST
2.4.5【推荐】 在 except 子句中重新抛出原有异常时,不能用 raise ex,而是用 raise。
try :
raise MyException()
except MyException as ex:
try_handle_exception()
raise
try :
raise MyException()
except MyException as ex:
log.exception(ex)
raise AnotherException(str (ex))
try :
raise MyException()
except MyException as ex:
try_handle_exception()
raise ex
2.4.6【推荐】 所有 try/except 子句的代码要尽可的少,以免屏蔽其他的错误。
try :
value = collection[key]
except KeyError:
return key_not_found(key)
else :
return handle_value(value)
try :
return handle_value(collection[key])
except KeyError:
return key_not_found(key)
2.5 条件表达式
2.5.1【推荐】 函数或者方法在没有返回时要明确返回 None。pylint:inconsistent-return-statements.
def foo (x ):
if x >= 0 :
return math.sqrt(x)
else :
return None
def bar (x ):
if x < 0 :
return None
return math.sqrt(x)
def foo (x ):
if x >= 0 :
return math.sqrt(x)
def bar (x ):
if x < 0 :
return
return math.sqrt(x)
2.5.2【推荐】 对于未知的条件分支或者不应该进入的分支,建议抛出异常,而不是返回一个值(比如说 None 或 False)。
def f (x ):
if x in ('SUCCESS' ,):
return True
else :
raise MyException()
def f (x ):
if x in ('SUCCESS' ,):
return True
return None
2.5.3【可选】 if 与 else 尽量一起出现,而不是全部都是 if 子句。
if condition:
do_something()
else :
pass
if condition:
do_something()
if condition:
do_something()
if another_condition:
do_another_something()
else :
do_else_something()
2.6 True/False 布尔运算
2.6.1【必须】 不要用 == 与 True、False 进行布尔运算。pylint:singleton-comparison.
if greeting == True :
pass
if greeting is True :
pass
2.6.2【必须】 对序列(字符串、列表、元组),空序列为 false 的情况。pylint:len-as-condition.
if not seq:
pass
if seq:
pass
if len (seq):
pass
if not len (seq):
pass
2.7 列表推导式
2.7.1【必须】 禁止超过 1 个 for 语句或过滤器表达式,否则使用传统 for 循环语句替代。
number_list = [1 , 2 , 3 , 10 , 20 , 55 ]
odd = [i for i in number_list if i % 2 == 1 ]
result = []
for x in range (10 ):
for y in range (5 ):
if x * y > 10 :
result.append((x, y))
result = [(x, y) for x in range (10 ) for y in range (5 ) if x * y > 10 ]
2.7.2【推荐】 列表推导式适用于简单场景。如果语句过长,每个部分应该单独置于一行:映射表达式,for 语句,过滤器表达式。
fizzbuzz = []
for n in range (100 ):
if n % 3 == 0 and n % 5 == 0 :
fizzbuzz.append(f'fizzbuzz {n} ' )
elif n % 3 == 0 :
fizzbuzz.append(f'fizz {n} ' )
elif n % 5 == 0 :
fizzbuzz.append(f'buzz {n} ' )
else :
fizzbuzz.append(n)
for n in range (1 , 11 ):
print (n)
fizzbuzz = [
f'fizzbuzz {n} ' if n % 3 == 0 and n % 5 == 0 else
f'fizz {n} ' if n % 3 == 0 else
f'buzz {n} ' if n % 5 == 0 else n
for n in range (100 )
]
[print (n) for n in range (1 , 11 )]
2.8 函数
2.8.1【必须】 模块内部禁止定义重复函数声明。pylint:function-redefined.
def get_x (x ):
return x
def get_x (x ):
return x
2.8.2【必须】 函数参数中,不允许出现可变类型变量作为默认值。pylint:dangerous-default-value.
def f (x=0 , y=None , z=None ):
if y is None :
y = []
if z is None :
z = {}
def f (x=0 , y=[], z={} ):
pass
def f (a, b=time.time( ) ):
pass
2.9 变量
2.9.1【必须】 禁止定义了变量却不使用它。pylint:unused-variable.
在代码里到处定义变量却没有使用它,不完整的代码结构看起来像是个代码错误。即使没有使用,但是定义变量仍然需要消耗资源,并且对阅读代码的人也会造成困惑,不知道这些变量是要做什么的。
def get_x_plus_y (x, y ):
return x + y
some_unused_var = 42
y = 10
y = 5
z = 0
z = z + 1
def get_x (x, y ):
return x
工具与配置
flake8 flake8 是一个结合了 pycodestyle,pyflakes,mccabe 检查 Python 代码规范的工具。
flake8 {source_file_or_directory}
在项目中创建 setup.cfg 或者 tox.ini 或者 .flake8 文件,添加 [flake8] 部分。
[flake8]
ignore =
W503,
E203,
exclude = .tox, .git, __pycache__, build, dist, *.pyc, *.egg-info, .cache, .eggs
max-line-length = 120
如果需要屏蔽告警可以增加行内注释 # noqa,例如:
example = lambda : 'example'
pylint 配置项较多,单独一个配置文件配置,详情可查阅:.pylintrc
pylint {source_file_or_directory}
如果遇到一些实际情况与代码冲突的,可以在行内禁用相关检查,例如:
try :
do_something()
except Exception as ex:
pass
如果需要对多行的进行禁用规则,可以配套使用 # pylint: disable=具体错误码 / # pylint: enable=具体错误码。
black black 是一个官方的 Python 代码格式化工具。
black {source_file_or_directory}
如果不想格式化部分代码,可以配套使用 # fmt: off/# fmt: on 临时关闭格式化。
EditorConfig EditorConfig 可以帮助开发同一项目下的跨多 IDE 的开发人员保持一致编码风格。
在项目的根目录下放置 .editorconfig 文件,可以让编辑器规范文件对格式。参考配置如下:
root = true
[*]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
end_of_line = lf
[*.py]
max_line_length = 120
[*.bat]
indent_style = tab
end_of_line = crlf
[LICENSE]
insert_final_newline = false
[Makefile]
indent_style = tab
本规范适用于所有使用 Python 语言作为开发语言的软件产品。
由于 Python2 在 2020 年停止维护,建议新增的项目使用 Python3.6+,可以使用到更多的高级特性。如果项目有兼容性需求需要支持老版本 Python 的,那么不涉及的特性可以忽略。本规范的示例采用符合 Python3.6+ 的语法。
必须(Mandatory) :用户必须采用;
推荐(Preferable) :用户理应采用,但如有特殊情况,可以不采用;
可选(Optional) :用户可参考,自行决定是否采用;
未明确指明的则默认为 必须(Mandatory) 。
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 curl 转代码 解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online