目录
Python 风格第一部分 - PEP8
CS106A 不仅仅教授编码。它一直教授如何以良好的风格编写干净的代码。您的部门负责人将与您讨论代码的正确性,并为您提供良好风格的指导。
杂乱的代码效果很差 — 难以阅读,难以调试。为了帮助您养成正确的习惯,我们希望您始终提交干净的代码,当然,我们所有的示例也应该具有良好的干净风格。
文字是可读的
良好风格的目标是“可读”的代码,这意味着当有人浏览代码时,代码的作用就会一览无余。
经验表明,可读性强的代码在构建和调试时耗费的时间更少。调试尤其会耗费大量时间,因此,学习编写干净的代码并保持代码干净是我们始终要做的事情。就像外科医生保持双手干净一样,这是正确的做法,我们会努力始终养成这种习惯。
可读性 1 - 函数和变量名称
实现良好可读性的第一步是良好的变量和函数名称,如以下示例所示:
...
url = 获取浏览器网址()
如果有安全问题(url):
display_alert(‘该网址看上去不太可靠!’)
别的:
html = 下载网址(网址)
显示html(html)
...
代码的叙述步骤从良好的函数和变量名称(本质上是叙述中的动词和名词)中显而易见。这里不需要其他注释。仅凭名称就使其具有可读性。
函数是代码中的操作,因此我们更喜欢使用动词名称,例如“display_alert”或“remove_url”,以说明函数的作用。变量就像代码中的名词,因此我们更喜欢使用能够反映变量存储内容的名称,例如“urls”或“original_image”或“resized_image”。我们将在 Style 2 文档中更详细地讨论命名
可读性 2 - PEP8 策略
Python 是一个协作、免费和开源项目。“PEP”(Python 增强提案)是 Python 开发中使用的书面提案。
PEP8是最早的 PEP 之一,它是一套用于编写“标准”风格 Python 的统一样式和格式规则,因此您的代码对于阅读或修改它的任何人来说都具有正确的外观。这非常类似于英语拼写改革,其中“public”是标准拼写,而“publick”已不再使用,看起来很奇怪,有点令人讨厌。
以下是我们将使用的最重要的 PEP8 规则。您提交的代码应遵守 PEP8。
缩进 4 个空格
用 4 个空格缩进代码。def/if/for/while 行以冒号结尾,其包含的行从下一行开始,所有行都缩进 4 个空格,如下所示:
如果颜色=='红色':
颜色='绿色'
打印(颜色)
在早期的 Python 中,有些人使用 2 个空格或制表符。这些做法已经消失,现在 4 个空格才是标准。
项目之间只有一个空格
大多数代码行都混合了变量和“运算符”,例如+ * / = >=
。使用一个空格将运算符和项与运算符彼此分隔:
边界 = x * 12 + 13
如果 x >= 4:
打印 (x + 2)
括号内无空格
左右括号和方括号与其内容之间没有空格隔开。函数调用的左括号紧挨着函数名:
run_along(1,2 * 3,'hi')
bark()
lst = [1,2,z * 6]
逗号/冒号后的空格
逗号或冒号后面有 1 个空格,但前面没有空格。
foo(1, 'hello', 42) # 逗号:前有 0 个空格,后有 1 个空格
[1, 2, 3] # 例如列表
{'a': 1, 'b': 2} # 例如字典
切片异常
切片是上述规则的一个例外。切片中的冒号可以没有空格,最常见的写法是这样的:
s[start:end + 1] # 切片 - 无空格
PEP8 规则是宽容的,即切片冒号不应有空格,如上所示,或者两边各有 1 个空格,像+
。
使用一致的引号
Python 字符串可以写在单引号中,如'Hello'
或双引号中,如 "there"
。PEP8 要求程序选择一种引号样式并始终如一地使用它。对于 CS106A,我们建议只使用单引号。单引号稍微简单一些,因为它不需要 Shift 键。不用考虑使用哪个引号,这样可以释放宝贵的脑细胞来做其他事情。
Def 前有 2 个空行
PEP8 要求文件中的每个 def 前有 2 个空行。这是较弱的 PEP8 规则之一。如果您的代码在函数之间有 3 行,我们不会对您的代码感到不满。
Def 中的空行
如果代码行有自然阶段 — 几行设置文件,几行排序键 — 使用 def 中的空行将这些阶段彼此分开,就像将文章分成几段一样。标准要求“谨慎”使用空行。
更喜欢!=
和not in
这是两种均能正常工作的等效形式之间的一种选择。我们更喜欢不相等和不属于测试的“快捷”形式,如下所示:
如果不是 s == 'donut':# 否
...
如果 s != 'donut':# 是
...
如果食物中没有 'donut':# 否
...
如果食物中没有 'donut':# 是
...
这些形式按照更符合自然措辞的方式排列代码,例如“s 不是甜甜圈”或“甜甜圈不在食物中”。
不要写:if x == True
在 if/while 测试中,布尔 True/False 的求值方式比表面上看起来要复杂一些。简单的规则是:不要在 if/while 测试中 写if x == True
或。if x == False
假设我们有一个print_greeting()
接受shout_mode
参数的函数。
不要这样写:
def print_greeting(words, scream_mode):
if scream_mode == True: # NO 不像这样
print(words.upper())
else
print(words)
结构本身if
可以区分True
与False
值。因此,编写代码以直接将布尔值赋予shout_mode
,if
如下所示:
def print_greeting(words, scream_mode):
if scream_mode: # YES 像这样
print(words.upper())
else:
print(words)
要反转逻辑,请不要使用== False
。not
像这样使用:
def print_greeting(words, scream_mode):
if not scream_mode:
print('没有喊叫')
else:
print(words)
从代码中删除通行证
Python 中的指令pass
是一个占位符行,实际上不执行任何操作。它很少用于常规生产代码。然而,在编码练习中,通常会有一些样板代码,其中标记了学生代码的位置。提交代码之前,请从代码中 pass
删除所有标记。pass
# 内联注释
最好添加 #“内联”注释来解释特别不明显或有趣的代码的作用。当代码本身可以很好地显示该行的作用时,内联注释是不需要的。
1. 对于以下几行,代码很好地说明了一切,因此除了好的变量和函数名称之外,不需要内联注释。大多数代码行都是这样的。
count += 1
total_len = len(名称) + len(地址)
特别是,避免添加重复代码本身内容的评论。
i += 1 # 将 i 加 1
2. 内联注释是合适的,如下例所示,解释一段不太明显的代码完成了什么——解决工作目标,而不是重新陈述所使用的运算符。
# 将 i 增加到下一个 10 的倍数
i = 10 * (i // 10 + 1)
内联注释提供了从行本身看不出来的有用信息。
3. 内联注释的另一个重要用途是指出代码未按其显示执行的情况。这说明了可读性 - 代码未按其变量和函数名称所暗示的那样执行,因此内联注释可以帮助澄清问题。
vendor.add('AT&T')
vendor.add('Stanford University')
vendor.add('T-Mobile')
# 注意:我们在这里传递“T-Mobile”,但由于历史
# 原因,支付系统重写并
在内部使用#“Vodafone”。
教学中使用的示例代码通常比常规生产代码具有更多的内联注释,因为在教学中我们很多时候想要指出或解释一行中显示的技术。
与之比较==
在 Python 中比较两个值的常用方法是什么?答案是:使用==
如下运算符:
if word == 'meh':
print('热情低落')
它适用于字符串、整数、列表,几乎适用于所有东西。了解==
运算符是最重要的。但是,下面有一个例外。
例外is None
比较运算符==
是比较任意两个值的常用方法,我们不会标记出仅使用 的 CS106A 代码==
。
但是 PEP8 中有一条规则要求使用不同的比较形式,因此您最终应该学习它。此外,您可能会注意到您的 Python 编辑器会因为这条 PEP8 规则而 None
抱怨比较。x == None
PEP8 要求与特殊值的比较None
,True
并且False
应该使用is
或is not
比较而不是==
,如下所示:
如果单词为 None:是,则“为 None”
打印('此处无)
如果结果不为 None:是,则“不为 None”
打印('得到结果')
如果单词 == None:否,则避免“== None”
打印('Nada')
到目前为止,此规则最常见的应用是针对值None
,因此您可以将其视为规则is None
。此要求的原因有些晦涩难懂,但如果您好奇的话,下面会解释。如果代码意外地使用了==
而不是,代码几乎肯定会完美运行。无法正确比较 的is
情况非常非常罕见。 ==
None
不幸的是,反之则不然。如果is
在程序员想要使用 的地方编写了 代码==
,那么它通常无法正常工作。因此,程序员应该关注==
哪个是常见且可靠的。程序员不应该将is
运算符视为经常使用的东西,除了这个关于 的强制性情况is None
。我们不会标记使用 的学生代码,而是在课堂上提到它时 == None
提及首选形式。is None
有关其操作的详细信息, 请参阅运算符部分。
为什么需要is None
?
您可能会认为is None
使用这种形式是is
因为与内存和副本有关,但其实是出于其他原因。之所以存在这种要求,是因为数据类型可以以这样的方式is None
提供自定义定义,即在实际为假的情况下声称为真。这是一种不合理的定义,但这是可能的,而且有时确实发生过。标准 Python 安装中没有数据类型具有这种奇怪的行为,这就是为什么它通常可以正常工作。但是,项目中的代码可能有这种行为,因此针对这种情况,PEP8 要求使用这种形式。这避免了该问题,因为数据类型可以自定义,但运算符不能自定义。 ==
x == None
==
== None
is None
==
is
长线的历史
在以前计算机显示器相对较小的时候,项目通常会有一个规则,即代码中的任何一行都不能超过 80 或 100 个字符,以便代码能够适合显示器。这种规则已经不那么常见了。通常在 Python 中,最简单的做法就是让长行保持长。
但是,如果一行太长,难以阅读或处理,则可以使用以下几种技巧将长行拆分为较短的独立行。
参数分解线
假设有一个函数调用行,由于参数很多所以很长,如下所示:
绘制背景形状(selected_shape.x,selected_shape.y,子宽度+边距,子高度*边距,selected_color)
为了分解这一长行,请在逗号后添加换行符,并缩进后面的行,以便参数具有与上面的参数相同的缩进,如下所示:
绘制背景形状(selected_shape.x,selected_shape.y,
子宽度+边距,子高度*边距,
selected_color)
用括号分隔长行
如果 Python 发现一行带有左括号(
而没有匹配的右括号,Python 会将后面的行视为第一行的延续,直到匹配成功。和也 )
适用。[
{
例如,假设有这个长的 if 测试:
如果 selected_x >= 0 且 selected_x < shape.width 且 selected_y >= 0 且 selected_y < shape.height:
返回 True
较长的测试表达式可以分成几行,用一对括号括起来。第二行及之后的行应再缩进4个空格,这样它们就不会意外地与后续的主体行对齐。
如果 (selected_x >= 0 且
selected_x < shape.width 且 # 额外缩进
selected_y >= 0 且
selected_y < shape.height):
返回 True
还有一种偏好是,每行的最后一个单词都是操作符,比如and
或+
,这样就强化了后面几行有更多内容的想法。
命名参数异常
项间 1 个空格规则有一个例外,但这种情况很少见。如果函数调用有命名参数,则不需要像这样在周围留空格=
:
打印('嗨',结束='')
我认为这里的原因是,这种用法=
与更常见的变量赋值不同=
,所以最好让这种用法看起来有点不同。
命名怪癖:
Python 关键字
一些词,例如def
、for
和 ,if
是 Python 中的固定“关键字”,因此您不能使用这些词作为变量或函数名称。以下是关键字列表:
>>>导入关键字
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
“len” 规则:不要使用内置函数作为变量名
Python 有许多内置函数,例如len()
和min()
。作为 Python 灵活性的一个奇怪例子,您的代码可以使用赋值=
来更改len
代码中的含义……这可能是一个巨大的错误!
>>> len('hello') # len 函数有效
5
>>> len = 7 # 将“len”重新定义为 7,这不是个好主意
>>> len('hello') # 哦不!
TypeError: 'int' 对象不可调用
这里有一个简单的规则:不要使用常用函数的名称作为变量名。以下是最常见的函数名称:
len abs min max int float list str dict 范围 map 过滤器格式
不需要记住所有要避免使用的函数名称列表,只需避免使用代码中使用的函数名称,通常是众所周知的函数,如、、len
等等。 range
min
顺便说一句,这就是为什么我们避免使用“str”或“list”作为变量名,而是使用“s”和“lst”。
以这种方式重新定义函数只会影响您的本地代码,而不会影响程序中其他地方的代码。因此,如果您的代码意外定义了名为 的变量divmod
,则不会干扰调用内置函数 的另一个函数中的代码divmod()
。
一个关于可读性的小笑话
对于读到这里的人来说,这是一个可选点。可读性是什么意思?可以说它意味着代码的视觉效果与它要执行的操作的语义相符。
考虑到这一点,您如何看待这段计算总分但间距在技术上违反 PEP8 的代码:
总分 = 分数*10 + 奖励*2
我认为它看起来还不错。虽然没有空格,但缺少的空格与优先级一致——乘法将首先发生,而缺少的空格在某种程度上强化了这一点。
这个版本怎么样?
总分 = 分数 * 10+奖金 * 2
看到这个,你可能会笑出声来或者皱眉头。这完全是错的,有点像笑话的妙语。这可能会让你稍微明白,代码的含义和它的外观有着某种深层次的联系。考虑到这种联系,看起来杂乱的代码更容易产生混淆和错误也许并不奇怪。