代码被阅读的次数远多于编写的次数。
我们可能花费很多时间来编写一段代码,一旦完成后大概率就再不会重新写它。当这段代码不仅是自己用时,就得注意了,每次自己或其他人浏览,需要快速知道它的作用及编写它的原因,因此可读性显得很重要,比如:
>>> a = "Cai Xukun">>> b, c = a.split()>>> print(b, c, sep=', ')
看到这种脑阔痛。那么,每个人都有自己的编码风格,如何使整个团队趋于一致呢?Python PEP 8早已考虑到这种情况:https://peps.python.org/pep-0008/。
我们可能互相不清楚每个人的风格,但又必须阅读与理解各自产出的代码,那么此时遵循PEP 8会是优秀选择,也是每个Python从业者需要学习掌握的规范,一起看看吧!
编写代码时需要命名很多东西,如变量、函数、类等。选择合理的名称将节省以后的时间和精力,确保能够从名称中得到某个变量或函数代表的意义,不恰当的名称还会徒增调试难度。
Tip:切勿使用 l 、 O 或 I 单字母名称,因为这些名称可能会被误认为 1 和 0。
以下是一些常见的命名约定以及如何使用示例,除了在代码中选择正确的命名样式之外,还必须仔细选择名称:
类型 | 命名约定 | 例子 |
Variable | 使用小写的单个字母、单词或单词,用下划线分隔单词 | x, var, my_variable |
Function | 使用一个或多个小写单词,用下划线分隔单词 | function, my_function |
Class | 每个单词都以大写字母开头,这种风格称为驼峰式命名法或帕斯卡式命名法 | Model, MyClass |
Method | 使用一个或多个小写单词,用下划线分隔单词 | class_method, method |
Constant | 使用大写的单个字母、单词或单词,用下划线分隔单词 | CONSTANT, MY_CONSTANT, MY_LONG_CONSTANT |
Module | 使用简短的小写单词,用下划线分隔单词 | module.py, my_module.py |
Package | 使用简短的小写单词,不要用下划线分隔单词 | package, mypackage |
在编写代码时对命名选择需要进行足够的思考,在Python中为对象命名的最佳方法是使用描述性的名称。
在命名变量时,可能会选择简单的、单个字母的小写名称。比如这篇文章开头的引例,要将一个人的姓名存储为字符串,并且想要使用字符串切片来以不同的方式格式化姓名吗,写成如下形式是不是更舒服?
>>> name = 'Cai Xukun'>>> first_name, last_name = name.split()>>> print(last_name, first_name, sep=', ')
同样地,为了偷懒,你可能在选择名称时使用缩写。如下示例中,定义了一个名为db()的函数,它接受一个参数x并将其乘2倍,乍一看,这似乎是一个明智的选择,db()是double的缩写,但在一段时间后再回到这段代码,可能已经忘记了这个函数实现什么,并为偷懒付出相应代价:
def db(x): return x * 2
以下写法则要清晰得多:
def multiply_by_two(x): return x * 2
相同的原则也适用于Python中所有其他数据类型和对象,始终尽量使用最简洁且具有描述性的名称总不会出错。
垂直空白,即空行,对于提升代码的可读性起着关键作用。密集堆叠的代码可能令人感到压抑,不易理解,同样地,代码中过多的空行则会让其看起来过于稀疏,带来不必要的滚动。
将顶层函数和类用两个空行隔开。顶层函数和类通常相对独立,承担不同的功能。因此,为其周围添加适量的垂直空间是合理的,这有助于清晰地标示它们的独立性:
class MyFirstClass: passclass MySecondClass: passdef top_level_function(): return None
用一个空行分隔类内方法定义:
class MyClass: def first_method(self): return None def second_method(self): return None
在函数内部使用空行以展示清晰的步骤。有时,一个复杂的函数在return之前需要完成多个步骤。为了帮助读者理解函数内部的逻辑,每个步骤之间留出一个空行会很有帮助。
在下面的示例中,有一个计算列表方差的函数。这是一个两步问题,通过在它们之间留出空行来表示每个步骤。在return之前也有一个空行,有助于清楚地看到返回了什么内容:
def calculate_variance(number_list): sum_list = 0 for number in number_list: sum_list = sum_list + number mean = sum_list / len(number_list) sum_squares = 0 for number in number_list: sum_squares = sum_squares + number**2 mean_squares = sum_squares / len(number_list) return mean_squares - mean**2
PEP 8建议将行限制在79个字符以内,但很多时候将语句限制在79个字符或更少并不总是可能的。PEP 8概述了语句跨越多行的方法。
如果代码包含在括号、方括号或花括号内,Python会假定它是行的延续:
def function(arg_one, arg_two, arg_three, arg_four): return arg_one
还可以使用反斜杠来换行:
from mypkg import example1, / example2, example3
如果需要在二元操作符(如+和)周围进行换行,应该在操作符之前进行*。这个规则源自数学,数学家们一致认为,在二元操作符之前换行可以提高可读性,可以立即看到正在相加或相减的变量,因为操作符紧邻正在操作的变量:
total = (first_variable + second_variable - third_variable)
现在,让我们看一个在二元操作符之后换行的示例:
total = (first_variable + second_variable - third_variable)
在这里,很难看出正在相加的变量和正在相减的变量。
在二元操作符之前换行会产生更可读的代码,因此PEP 8鼓励这样做。
缩进在Python中非常重要。在Python中,代码行的缩进级别决定了语句如何分组在一起。
考虑以下示例:
x = 3if x > 5: print('x is larger than 5')
缩进的打印语句告诉Python只有在if语句返回True时才执行它。相同的缩进规则适用于在调用函数时告诉Python要执行哪些代码,或者哪些代码属于给定的类。
PEP 8规定的关键缩进规则如下:
如上所述,在缩进代码时应该使用空格而不是制表符。当按下Tab键时,可以调整文本编辑器的设置,将制表符字符输出为4个空格。
Python 3不允许混合使用制表符和空格。如果正在使用Python 3,则会抛出这些错误:
$ python3 code.py File "code.py", line 3 print(i, j) ^TabError: inconsistent use of tabs and spaces in indentation
可以使用制表符或空格来指示缩进的Python代码。但是,如果使用的是Python 3,必须在选择上保持一致,否则,代码将无法运行。
当使用行延续将行保持在79个字符以下时,使用缩进来提高可读性非常有用。帮助区分两行代码和跨越两行的单行代码。可以使用两种缩进样式,第一种是将缩进块与起始分隔符对齐:
def function(arg_one, arg_two, arg_three, arg_four): return arg_one
有时,只需要4个空格与起始分隔符对齐。这通常发生在跨多行的if语句中,因为if、空格和起始括号共计4个字符。在这种情况下,很难确定if语句内部的嵌套代码块从哪里开始:
x = 5if (x > 3 and x < 10): print(x)
在这种情况下,PEP 8提供了两种改进可读性的替代方法:
x = 5if (x > 3 and x < 10): # Both conditions satisfied print(x)
x = 5if (x > 3 and x < 10): print(x)
换行后的另一种缩进样式是悬挂缩进,悬挂缩进即段落或语句中除了第一行外的每一行都缩进。可以使用悬挂缩进来在视觉上表示代码行的延续:
var = function( arg_one, arg_two, arg_three, arg_four)
当使用悬挂缩进时,第一行不得有任何参数。
使用悬挂缩进时,添加额外的缩进以区分连续的行与函数内部的代码。如以下示例很难阅读,因为函数内部代码与连续的行处于相同的缩进级别:
def function( arg_one, arg_two, arg_three, arg_four): return arg_one
相反,最好在行延续上使用双重缩进。这有助于区分函数参数和函数体,提高可读性:
def function( arg_one, arg_two, arg_three, arg_four): return arg_one
行延续允许在括号、方括号或大括号内换行。但很容易忽略闭合括号的位置,将它放在合适的地方很重要。PEP 8提供了两个选项来确定隐式行延续中闭合括号的位置。
将闭合括号与前一行的第一个非空白字符对齐:
list_of_numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
将闭合括号与开始构造的行的第一个字符对齐:
list_of_numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9]
可以自由选择使用哪个选项,但请保持一致。
使用注释来记录代码的编写以便自己和任何合作者都能理解。在添加注释到代码时,请记住以下要点:
块注释非常有用,帮助他人理解给定代码块的目的和功能,PEP 8为编写块注释提供以下规则:
以下是解释for循环功能的块注释示例。为保持79字符行限制,句子被换行:
for i in range(0, 10): # Loop over i ten times and print out the value of i, followed by a # new line character print(i, '/n')
有时,如果代码技术含量高,那么在块注释中使用多个段落是必要的:
def quadratic(a, b, c, x): # Calculate the solution to a quadratic equation using the quadratic # formula. # # There are always two solutions to a quadratic equation, x_1 and x_2. x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a) x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a) return x_1, x_2
如果不确定哪种注释类型适合,通常可以选择使用块注释。
行内注释用于解释代码片段中的单个语句。以下是PEP 8关于行内注释的建议:
以下是行内注释的示例:
x = 5 # This is an inline comment
有时,行内注释是必要的,但可以使用更好的命名约定来替代:
x = 'John Smith' # Student Name
在这个示例中,行内注释确实提供了额外的信息。但是,将“x”作为人名的变量名是很呆的做法,如果更改变量名称,就不需要行内注释:
student_name = 'John Smith'
最后,诸如以下的行内注释是不好的习惯(脱裤子放P),因为陈述了显而易见的事实并且会使代码混乱:
empty_list = [] # Initialize empty listx = 5x = x * 5 # Multiply x by 5
文档字符串,docstrings,是出现在任何函数、类、方法或模块的第一行的双引号(“”")或单引号(‘’')括起来的字符串。用于解释和记录特定的代码块。PEP 257有专门阐述docstrings,docstrings最重要规则如下:
def quadratic(a, b, c, x): """Solve quadratic equation via the quadratic formula. A quadratic equation has the following form: ax**2 + bx + c = 0 There always two solutions to a quadratic equation: x_1 & x_2. """ x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a) x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a) return x_1, x_2
def quadratic(a, b, c, x): """Use the quadratic formula""" x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a) x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a) return x_1, x_2
在表达式和语句中适当使用空格可以非常有助于阅读。如果没有足够的空格,代码可能会难以阅读,因为它们都挤在一起。如果空格过多,则在语句中可能很难在视觉上组合相关术语。
在以下二元操作符的两侧都加上单个空格:
Tip:当使用 = 为函数参数分配默认值时,不要用空格如:def function(default_parameter=5):
当语句中有多个操作符时,在每个操作符前后都添加单个空格可能会显得混乱。相反,最好只在具有最低优先级的操作符周围添加空格,特别是在进行数学操作时。以下是几个示例:
# Recommendedy = x**2 + 5z = (x+y) * (x-y)# Not Recommendedy = x ** 2 + 5z = (x + y) * (x - y)
还可以将此应用于具有多个条件的if语句:
# Not recommendedif x > 5 and x % 2 == 0: print('x is larger than 5 and divisible by 2!')
在上面的示例中,and操作符具有最低优先级。因此,以下方式可能更清晰地表示:
# Recommendedif x>5 and x%2==0: print('x is larger than 5 and divisible by 2!')
可以自由选择哪种更清晰,但请注意,操作符两侧必须使用相同数量的空格。
在切片中,冒号充当二元操作符。因此,适用于前一节中概述的规则,两侧应具有相同数量的空格:
list[3:4]# Treat the colon as the operator with lowest prioritylist[x+1 : x+2]# In an extended slice, both colons must be# surrounded by the same amount of whitespacelist[3:4:5]list[x+1 : x+2 : x+3]# The space is omitted if a slice parameter is omittedlist[x+1 : x+2 :]
在某些情况下,添加空格可能会使代码更难阅读。PEP 8明确提供了一些不适合使用空格的示例。
最容易出Bug的是在行末,即尾随空格。因为它是不可见的,可能会产生难以追踪的错误,以下概述了一些应避免添加空格的情况:
# Recommendedmy_list = [1, 2, 3]# Not recommendedmy_list = [ 1, 2, 3, ]
# Recommendedprint(x, y)# Not recommendedprint(x , y)
def double(x): return x * 2# Recommendeddouble(3)# Not recommendeddouble (3)
# Recommendedlist[3]# Not recommendedlist [3]
# Recommendedtuple = (1,)# Not recommendedtuple = (1, )
# Recommendedvar1 = 5var2 = 6some_long_var = 7# Not recommendedvar1 = 5var2 = 6some_long_var = 7
# Not recommendedmy_bool = 6 > 5if my_bool == True: return '6 is bigger than 5'
在这里使用等价运算符(==)是不必要的,bool只能取True或False的值,以下写法已足够,PEP 8鼓励使用它:
# Recommendedif my_bool: return '6 is bigger than 5'
如果要检查列表是否为空,首先会想要检查列表的长度,如果列表为空,它的长度为0,在if语句中使用时等效于False:
# Not recommendedmy_list = []if not len(my_list): print('List is empty!')
然而,在Python中,任何空列表、字符串或元组都是False。因此,可以找到一个更简单的替代方案:
# Recommendedmy_list = []if not my_list: print('List is empty!')
虽然这两个示例都会输出"List is empty!",PEP 8鼓励使用第二个方式。
# Recommendedif x is not None: return 'x exists!'
不要写成以下形式:
# Not recommendedif not x is None: return 'x exists!'
在检查字符串是否以特定词开头或结尾时,使用.startswith()和.endswith()而不是切片:
# Not recommendedif word[:3] == 'cat': print('The word starts with "cat"')
使用.startswith():
# Recommendedif word.startswith('cat'): print('The word starts with "cat"')
同样的原则也适用于检查后缀:
# Recommendedif file_name.endswith('jpg'): print('The file is a JPEG')
以上就是本期的全部内容,如果想了解更多关于PEP 8的细节可以访问:https://pep8.org/。
别忘了点赞再看哈,我是啥都生,下期再见!
本文链接:http://www.28at.com/showinfo-26-17554-0.htmlPython:求求按规范写我
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: 提升您的 Go 应用性能的六种方法
下一篇: Go的插件机制:动态加载与卸载