面向青少年的-Python-教程-五-

60 阅读54分钟

面向青少年的 Python 教程(五)

原文:Python for teenagers

协议:CC BY-NC-SA 4.0

十三、错误处理

我们正在迅速接近这本书的结尾,我们的时间一起冒险。很快,你将独自披上斗篷,在没有我的帮助下与邪恶的人战斗(当然,这只是你的想象!),而且全靠自己写代码。

治愈悲伤的音乐。

尽管现在,我们仍然是超级英雄组合!虽然我们已经学会了如何击败许多编程恶棍,克服许多不同的障碍,但有一个话题我们仍然需要讨论:如何克服我们自己的失败。

你说失败?什么样的英雄或程序员会失败?

可悲的是,我们都有。或者,从更好的角度来看:幸运的是,我们都有。

为什么幸运?因为失败是让我们变得更强大、提高技能和编程能力的最好方式之一。

想想这个:你知道为什么举重会练出肌肉吗?这是因为你撕裂的肌肉需要愈合。当你举重时,在某一点上你达到了一个你不能再举的点——也就是说,你失败了。这种失败正是健身者所期待的,因为他们知道只有当你的肌肉失败时,它们才能开始修复损伤并变得更加强壮。

你的编程技巧一模一样。在我看来,真正理解代码的唯一方法是把它搞砸,然后找出你做错了什么。任何人都会这门语言——然而,理解这门语言需要多年的失败。

注意,同样的逻辑不适用于你的代数考试…不要不及格!

到目前为止,当我们遇到问题时,我们只是阅读我们的。py 文件,一行一行,试图找出哪里出了问题。老实说,没有真正的失败——只要你完全按照我写的输入我的例子。

然而,很可能是你打错了一两个单词,导致你的程序失败。在那之后你所做的——如果你已经做到了这一步——就是搜索你的代码,寻找引起问题的罪魁祸首,拼写错误的单词或缩进,然后修复它。

如果发生了这种情况,那么恭喜你——你已经正式测试并调试了一个程序,即使只是在最基本的意义上。

调试对我们来说是一个新词。它意味着从我们的代码中识别和删除错误。

让我们再来看看这个定义:从我们的代码中识别并移除错误。

对我来说,调试过程中最重要的部分是找到错误。从那里,我们必须了解错误,只有这样,我们才能修复或消除导致错误的问题。

对于小程序,我们可以逐行查找问题。对于较大的程序,我们会希望使用一个叫做调试器的程序。

查找错误

Python 通常很擅长告诉我们我们把事情搞砸了。对于本节,让我们继续创建一个名为Oops.py的新文件。

这个文件将会充满错误,当你运行你的程序时,你会被 IDLE 吼到。当我们键入我们的代码时,代码中的错误对你来说可能很明显,也可能不明显;不管怎样,跟着做,如果你看到了错误,假装你没有看到;它将帮助您了解如何更好地修复程序。

Oops.py中输入以下代码:

print hello

对于精明的程序员来说,你可能已经看出问题了;如果是这样,恭喜你,但假装你没有。继续运行程序,看看会发生什么。完了?你收到错误信息了吗?你当然知道!它应该是这样的:

Missing parentheses in call to 'print'. Did you mean print(hello)?

这应该显示为弹出消息。如你所见,IDLE 非常聪明——它不仅发现了你的代码中存在的问题,还为你提供了如何修复它的建议。

这里需要注意一些事情。首先,虽然 IDLE 在这里确实提供了一个建议,但它实际上是不正确的。由于我们没有将想要打印的文本用引号括起来,IDLE 假设我们真的试图打印一个变量,并向我们展示了如何打印一个名为hello的变量。

在这种情况下,这不是我们的意图,但 Python 指出错误并提供可能的解决方案还是不错的。

我们真正想要做的是打印出单词“hello”,这当然就像键入 print(“Hello”)一样简单。然而,请记住,我们希望我们的程序失败。

那么第一个错误的教训是什么?有时 IDLE 会在弹出消息中给我们一个错误消息,并建议错误发生的位置和可能的解决方案——可能正确也可能不正确。

现在,让我们修改文件中的代码,使其与下面的代码匹配:

print("Hello)

同样,您可能已经发现了问题——我们忘记用第二个或结束引号来结束我们的print()函数——但是继续运行程序看看会发生什么。

这里,我们再次看到另一个弹出窗口。这一次,我们得到了一种不同类型的错误——生产线末端(EOL)错误。它应该说:

EOL while scanning string literal.

在这里,Python 基本上是在告诉我们,我们没有正确地关闭这条线,我们知道我们没有这样做。如果我们单击弹出窗口上的“OK”按钮,IDLE 应该会将我们带回到我们的文件,并以红色突出显示该行的其余部分——这表明它认为该区域有错误。

我们知道问题在于我们只是忘记了我们的第二个引号。我们将解决这个问题,但是这一次,让我们去掉第二个括号,看看会发生什么。编辑您的代码以匹配以下内容,然后再次运行:

print("Hello"

这一次,我们得到另一个错误弹出窗口。这是一个文件尾(EOF)错误,它说:

解析时出现意外的 EOF。

这一次,当我们单击“OK”时,Python 突出显示了代码下面的行。为什么会这样?

当我们运行我们的代码时,Python 在寻找我们代码行的结尾——它应该是一个右括号。相反,它没有发现关闭,所以它跳到下一行寻找更多的代码。当它也没有找到右括号时,它认为我们弄错了,并突出显示了这一行,告诉我们它在哪里遇到了错误。

这很重要,因为通常我们认为 Python 是在向我们展示错误在哪里;事实上,Python 向我们展示了它出错的地方(那是一个词吗?).把它想象成从跳水板的边缘跑下来;从跳板上下来的第一步就是你搞砸的地方,但是你可能直到在全班同学面前笨拙地俯卧并脱掉泳裤的那一刻才意识到这一点。

Python 也是如此。

下一个错误。

现在,让我们修改代码,使其与以下内容匹配:

prant("Hello")

保存文件并运行它。这次没有弹出窗口——我们一定做得很好!

不完全是。

这一次,当程序试图在 Python Shell 中运行时,我们会得到以下结果:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 1, in <module>
    prant("Hello")
NameError: name 'prant' is not defined

这种类型的错误称为命名错误。让我们仔细检查输出的每一部分。

第一行写着:

追溯(最近一次通话持续时间):

这是 Python 告诉你它正在追溯代码中的错误,最后一个调用出现在最前面。这一轮我们只有一个错误,但是不要担心,我们马上会有多个错误。

接下来,Python 告诉我们一些重要的信息。它告诉我们文件的位置(你的和我的不同)以及它认为错误在哪一行。在这种情况下,它表示第 1 行,即代码的第一行。

接下来,它向我们展示了发生特定错误的代码:prant("Hello").

最后,它告诉我们错误的类型,并提供了更多的细节:名称“prant”没有定义。

当我们看到这样的消息时,意味着 Python 看到了:

prant()

并且在其内置函数列表中找不到它。原因?因为它不存在——我们拼错了print(),虽然我们知道这一点,但 Python 无从得知。

由于 Python 没有找到名为prant()的内置函数,它假设我们正在尝试调用我们创建的名为prant()的函数。因为我们没有使用那个名称创建函数,所以 Python 认为我们输入了错误的名称或者没有定义那个名称的函数。

这是一个非常基本的错误,对于我们来说,跟踪和修复它非常简单。我们要做的就是看第 1 行,找到乱七八糟的代码,把prant("Hello")改成print("Hello")。然后,如果我们保存了它,我们可以运行它,一切都会好的。

当然,我们现在还不需要这么做,因为我们仍然在代码中故意犯错。

在我们继续之前,让我们看看我们是否能犯更多类型的错误。再次修改您的代码,使其符合以下内容:

a = 1

whilst a < 4:
    print(a)
    a = a + 1

这段代码应该做的是将值 1 赋给变量“a”。然后,我们创建了一个while循环,只要'a'的值小于4,它就会进行迭代或重复。

对于这个循环的每一次迭代,'a'的值被打印出来,我们还将+1加到'a'的值上。理论上,这段代码的输出应该是:

1
2
3

然而,我们在代码中犯了另一个错误——这次你能发现它吗?

如果您运行该代码,您将得到一个弹出框形式的提示,内容如下:

invalid syntax.

那到底是什么意思?这意味着我们在代码中拼错了。同样,我们用红色高亮显示我们的区域在哪里。

问题?我们把while拼成了*,而不是*。

让我们修正的拼写,但是在它的位置上犯另一个错误。编辑代码,使其与以下内容匹配:

a = 1
while a < 4
    print(a)
    a = a + 1

这次你能发现错误吗?保存文件并运行代码。再次,我们得到一个语法错误,即使我们修正了while的拼写。其他每个单词的拼写都是正确的,这是怎么回事呢?

语法错误包括一般的拼写错误,而不仅仅是拼写错误。在这种情况下,我们忘记在 while 语句的末尾添加一个冒号:。这一行应该是:

while a < 4:

如果您在末尾添加冒号并保存文件,它应该可以正常运行。

错误类型

实际上,Python 中只有三种主要的错误类型:语法错误、逻辑错误和异常。我们将在本节中介绍每种错误类型以及如何处理它们。所以,带上你的超级英雄护目镜,让我们准备好解决这个世界的问题吧!

好吧,好吧——也许只是我们代码中的问题。

句法误差

我们已经在前面的错误概述中讨论了一点语法错误。提醒您一下,当 Python 无法理解或读取一行代码时,会出现语法错误。

语法错误通常是由简单的打字错误引起的;也许您拼错了一个函数,或者忘记在语句末尾添加一个冒号。把它们当成语法或拼写错误。

在您收到的所有错误中,语法错误可能是最常见的。这有好有坏;这很好,因为这意味着,大多数情况下,你的错误只是拼写或标点符号的问题,而不是编程逻辑的问题。这很糟糕,因为,嗯,追踪它们可能会很烦人,尤其是在你整天夜以继日地输入代码后,你的眼睛会变得模糊。

绝大多数语法错误都是致命的,会导致代码无法执行,这也是塞翁失马焉知非福。虽然你的代码根本不工作可能很烦人,但这也确保了你不会发布一个有隐藏问题的软件。

如果遇到语法错误,请注意 IDLE 中突出显示红线的位置,或者注意出现错误的行号,并查找拼写、缩进、冒号、引号和括号使用方面的任何问题,或者无效参数。

逻辑错误

所有错误中最成问题的是可怕的逻辑错误。顾名思义,当您的编程逻辑中存在缺陷时,就会出现这种情况。这些类型的错误会导致你的程序行为古怪或者彻底崩溃。

逻辑错误如此令人沮丧的部分原因是,它们并不总是导致明显的错误。有时 Python 甚至没有捕捉到错误,而您自己可能会错过它。这就是为什么频繁测试代码并尽可能提供文档是如此重要。

有几种方法可以发现这些类型的错误,包括使用一个调试程序,我们将在本章的后面介绍。处理逻辑错误的最好方法是首先防止它们。我们通过提前规划程序和频繁测试来做到这一点。使用流程图可以帮助您确定代码的每个部分应该如何流动,并且是避免逻辑错误的有用工具。

当然,逻辑错误还是会发生;这只是作为程序员的一部分。

这是一个逻辑程序的例子——看看你是否能找出为什么这个程序会返回一个不是预期的结果。这里有一个提示:这个程序的目的是找到两个数字的平均值:

a = 10
b = 5

average = a + b / 2

print(average)

如果你不擅长数学,不要担心;当我们写这个程序时,我们期望 10 和 5 的平均值是 7.5;然而,当我们运行这个程序时,我们得到的结果是:

12.5

这当然是不对的。为什么会这样?让我们检查一下我们的数学,看看我们的计算是否正确。

如果我们在一张纸上写下这个等式,我们会写出 a+b/2——就像我们看到的那样。a + b 等于 15,除以 2 等于 7.5 对吗?

如果您还记得我们关于数学运算符和数字的讨论,那么在 Python 中,数学并不总是与使用笔和纸时一样。在 Python 中,有一个优先顺序,这意味着 Python 查看一个等式,并确定在继续下一部分之前先解决哪个部分。

如果这一部分不清楚,我鼓励你回到处理操作符和数字的那一章,再复习一遍。有意义的时候再回来。

为了让 Python 按照我们想要的顺序执行等式,我们需要使用括号()强制优先级顺序。在不出现逻辑错误的情况下,编写这段代码的真正方法应该是:

a = 10
b = 5

average = (a + b) / 2

print(average)

这一次,如果您运行代码,您将得到:

7.5

对于那些对数学不感兴趣的人,或者那些睡眠不足的人,你可能完全忽略了这个事实:这段代码根本没有正常运行。Python 根本没有发送警告或错误消息,所以如果我们不测试结果并仔细检查以确保它们是正确的,我们就没有真正的方法知道有问题。

现在想象一下,如果这是一个银行应用的一部分,您会看到一个简单的逻辑错误会如何毁掉整个系统,并让许多人非常难过!

例外

异常是一种特殊的错误。有几种类型的内置异常,但它们太多了,本章无法一一介绍。相反,您可以访问 Python。org 关于内置异常的文档页面位于 https://docs.python.org/3/library/exceptions.html#bltin-exceptions 查看不同的类型。一会儿我会解释为什么这可能比你想象的更有用。

现在,要知道当 Python 理解你的代码,但是不能执行基于它的动作时,异常就会发生。例如,也许你正试图连接到互联网,从网站上删除或复制一些数据,但你无法连接。或者你有一个脚本试图使用一个在你给它的地址上已经不存在的 API。

异常在许多方面不同于语法错误。其中之一是它们并不总是导致错误。这有好有坏;这很好,因为您的问题有时仍然可以异常运行;这是不好的,因为,嗯,你的程序有时仍然可以运行异常!

我们不希望我们的代码运行时出错!

关于异常的伟大之处——如果你想看到光明的一面——是我们可以做一些叫做异常处理的事情。处理一个异常基本上意味着我们预期错误可能发生,然后编写一个处理它们的方法。

假设我们有一个程序要求用户输入四位数的 pin 码。我们希望确保该值本质上是数字。我们已经将变量设置为专门保存一个整数值。让我们从基本代码开始:

pin = int(input("Enter your pin number: "))

print("You entered pin: ", pin)

如果你把代码放在一个文件中并运行它,它会要求你输入密码。继续尝试吧——如果你愿意,你可以把它添加到你的Oops.py文件中。首先,输入一个四位数,然后按下Enter。该程序将给出类似于以下内容的响应:

You entered pin: 1234

其中1234是您输入的任何数字。

现在,再次运行该程序,只是这一次,在提示时输入类似于“abcd”的内容,然后按下Enter

这样,您将获得以下输出:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 17, in <module>
    pin = int(input("Enter your pin number: "))
ValueError: invalid literal for int() with base 10: 'abcd'

这里,我们看到了一个类型为 ValueError 的异常错误。发生这种情况是因为 Python 期望在变量pin中找到的值的类型是整数;相反,你输入了一个字符串。

我们可以确保 Python 不会抛出这样的错误并迫使我们的程序不能正常运行的方法之一是提前处理错误。因为我们知道有人可能在我们的变量中输入了错误的数据类型,所以我们可以创建代码在错误发生时捕捉并处理它。

尝试键入以下代码,替换其他版本的代码,然后保存文件并运行它:

# Example of exception handling a ValueError

try:
    pin = int(input("Enter your pin number: "))
    print("You entered: ", pin)
except ValueError:
        print("You must only enter a numeric value.")

这在 Python 中被称为tryexcept块。它的具体目的是捕捉并处理异常。在某种意义上,块中包含的代码被小心处理;Python 意识到你打算在错误发生时处理它,如果存在一个错误(你指定的类型),它就触发你的except语句。

继续运行这个程序,当再次提示时输入'abcd',看看代码现在是如何运行的。您应该会得到这样的回应:

Enter your pin number: abcd
You must only enter a numeric value.

一旦 Python 点击了 except 语句,它就会遵循您的指令,然后退出程序。在现实生活中,我们希望将这段代码放在一个循环中,这样如果出现异常,它就会重新开始。例如,您可以使用一个简单的 while 循环,如下所示:

# Example of exception handling a ValueError
repeat = 1

while repeat > 0:

    try:
        pin = int(input("Enter your pin number: "))
        print("You entered: ", pin)
        repeat = 0
    except ValueError:
        print("You must only enter a numeric value.")
        repeat = 1

Try Except Else 块

你可以做的另一件事是创建一个Try Except Else块。这背后的想法是,如果没有异常,代码将执行一组不同的指令。例如:

# Example of exception handling a ValueError
# Using a Try Except Else block
# Enclosed in a while loop

repeat = 1

while repeat > 0:

    try:
        pin = int(input("Enter your pin number: "))
    except ValueError:
        print("You must only enter a numeric value.")
        repeat = 1
    else:
        print("You entered: ", pin)
        repeat = 0

这与之前版本的程序有着相同的结果和相似的工作方式。区别?它更简洁,可读性更强。它基本上读作:

Try this code. If it doesn't work:
Execute some code if an exception occurs.
Else if there are no exceptions, run this code.

最终使用

我们还可以添加一个东西到我们的块中——finally子句。当我们希望一些代码无论如何都要运行时——即使有错误——?? 是有用的。

# Example of exception handling a ValueError
# Using a Try Except Else Finally block

try:
    pin = int(input("Enter your pin number: "))
except ValueError:
    print("You must only enter a numeric value.")
else:
    print("You entered: ", pin)
finally:
    print("Are we done yet?")

为了更好地研究这段代码,我们移除了与repeat相关的while循环和repeat变量/代码。基本上这段代码是这样说的:

Ask for a pin number that is an integer value.
If the pin number is not an integer,
Trigger the except statement.
Else print the value of the pin number.
Additionally, no matter what,
Trigger the finally clause.

如果输入'abcd'并触发异常,这段代码的结果将是:

Enter your pin number: abcd
You must only enter a numeric value.
Are we done yet?

如果您再次运行它并输入'1234'作为您的 pin,它将导致:

Enter your pin number: 1234
You entered:  1234
Are we done yet?

无论哪种方式,你都会注意到,我们的finally子句被触发——正如预期的那样。如果您预料到了异常错误,这是让您的程序继续运行的好方法。

创建自定义例外

除了从定义的内置异常列表中设置处理异常,我们还可以创建一个自定义异常。为此,我们使用raise。这里有一个简单的例子:

super_name = "Afraid-of-Spiders-Man"
villain = "spiders"

if villain == "spiders":
    raise Exception("Yeah, no thanks...my name says it all...villain should NOT equal spiders!")

这里我们开始创建两个变量。一个保存着我们的超级英雄的名字—super_name,而另一个保存着我们的英雄将会遇到的反派类型—villain

接下来,我们执行一个 if 检查,看看villain的值是否等于'spiders'(毕竟,我们的英雄叫害怕蜘蛛的人!).因为villain确实匹配'spiders',所以我们使用raise来创建一个例外:

当我运行代码时,我得到以下错误:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 33, in <module>
    raise Exception("Yeah, no thanks...my name says it all...villain should NOT equal spiders!")
Exception: Yeah, no thanks...my name says it all...villain should NOT equal spiders!

注意

您可以忽略本例中的行号——我的文件中有其他代码,使错误出现的行号与您的不同。

这里我们看到异常错误被引发,打印出一些文本,内容如下:

Exception: Yeah, no thanks...my name says it all...villain should NOT equal spiders!

在这个例子中,我试图变得有趣,所以我破例说了一个笑话。实际上,当您创建自己的例外时,您会让他们说一些类似以下的话:

Exception: the villain variable contains a value that is not allowedspiders

这样,如果有人输入了错误的值,我们可以在查看异常时立即知道问题是什么,而不必追踪问题。

我们可以创建的另一种自定义异常是AssertionError异常。这种类型的异常通过断言给定条件为True或满足来启动程序。如果是,那么程序可以继续运行。否则,将引发 AssertionError 异常。

请考虑下面这段简短的代码:

assert 1 + 1 == 2, "One plus One does equal 2!"
assert 2 + 2 == 5, "2 + 2 does not equal five! Error in line 2!!"

这里我们有两个assert语句。如果我们运行这个程序,程序的第 1 行什么也没有发生——这是因为等式 1 + 1 实际上等于 2,所以断言条件测试等于True

当试图执行第二行代码时,assert测试条件证明了False (2 + 2 不等于 5),因此触发 AssertionError,产生以下输出:

Traceback (most recent call last):
  File "C:/Users/James/AppData/Local/Programs/Python/Python36-32/Oops.py", line 2, in <module>
    assert 2 + 2 == 5, "2 + 2 does not equal five! Error in line 2!!"
AssertionError: 2 + 2 does not equal five! Error in line 2!!

为了方便起见,我继续添加了代码中的错误写在了assert的输出中,以及引发 AssertionError 的原因。

记录

我们可以使用的另一个工具是使用logging来查找代码中的错误——特别是对于较长的程序。有几种方法可以做到这一点,但是最简单的方法可能是导入logging模块。

程序员用来减少代码中错误的一种方法是使用print()来验证一切都正常工作。例如,假设我有一组随机生成的统计数据——正如我们在超级英雄生成器 3000 应用中所做的那样。

我可以相信我的代码工作正常,并假设统计数据是随机生成的,但这可能不是最明智的做法。为了确保我正确地编写了所有代码,我可能希望随机生成姓名,然后临时插入一些代码来打印这些统计数据的结果。一旦我对随机数生成工作正常感到满意,我就可以删除所有的print()并继续我的代码。

例如,我可能会先编写以下代码:

import random

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

brains = random.randint(1,20)
braun = random.randint(1,20)
stamina = random.randint(1,20)
wisdom = random.randint(1,20)
constitution = random.randint(1,20)
dexterity = random.randint(1,20)
speed = random.randint(1,20)

然后,意识到我需要检查所有的值是否正确随机化,我可能会返回并编辑我的代码来添加这些print()函数:

import random

brains = 0
braun = 0
stamina = 0
wisdom = 0
power = 0
constitution = 0
dexterity = 0
speed = 0

brains = random.randint(1,20)
print("Brains: ", brains)
braun = random.randint(1,20)
print("Braun: ", braun)
stamina = random.randint(1,20)
print("Stamina: ", stamina)
wisdom = random.randint(1,20)
print("Wisdom: ", wisdom)
constitution = random.randint(1,20)
print("Constitution: ", constitution)
dexterity = random.randint(1,20)
print("Dexterity: ", dexterity)
speed = random.randint(1,20)
print("Speed: ", speed)

然后我可以做的是运行程序一次,看看变量中是否存储了值,给我结果:

Brains:  19
Braun:  19
Stamina:  2
Wisdom:  11
Constitution:  14
Dexterity:  12
Speed:  6

然后,对值被添加感到满意,我将再运行一次测试,以确保每次程序运行时值都被随机化。测试很简单:如果第二次的值不同,就可以了。结果呢?

Brains:  20
Braun:  2
Stamina:  14
Wisdom:  18
Constitution:  6
Dexterity:  19
Speed:  3

因为在我的两次测试中,每个 stat 的值都不同,所以我可以假设我对random的使用是正确的。我不再需要我的print()函数。我可以将它们注释掉,或者完全删除它们。

由于这是一段简单的代码,我将继续删除print()函数,这样我的代码可读性更好。

与其用一堆 print()函数把我的文件弄得乱七八糟,我可以使用日志来监视文件,并将结果写入一个单独的文本文件。

日志记录的另一个好处是我们可以记录代码中发生的事件和错误,以备将来出现新的 bug 或者我们需要查看日志。

值得注意的是,日志记录不仅仅是监视警告和错误;它对于监控触发事件也很有用。

事实上,logging模块有自己的一套“重要程度”等级,您可以在记录时使用。它们是:

Critical:用于可导致程序出现严重问题或根本无法运行的严重错误。

错误:对于严重的非关键问题

警告:用于意想不到的事情已经或可能发生的时候

Info:用于确认您的代码正在按预期运行——类似于我们对print()语句的使用

调试:有助于诊断任何问题,并提供可能有助于调试过程的信息

事实上,日志尤其是日志模块的使用超出了本书的范围。要用整整一章的时间来解释它的用法,虽然我鼓励初学者学习日志,但它根本不适合我们的课程。

也就是说,留出一些时间来阅读关于日志和logging模块的官方 Python 文档。此外,在创建更复杂的程序时,可以看看互联网上的一些教程和其他更高级的书籍,并开始涉猎日志记录。

把你的脚趾伸进去,当你感到舒服的时候,就开始潜水吧!

Python 调试工具

我们讨论了很多关于修复代码中的错误、测试代码以及如何执行异常处理的内容。我们还讨论了日志记录和使用logging模块跟踪日志文件中的错误和事件的基本概念。

我们可以用来解决编码问题的另一个超级英雄锦囊妙计是一个叫做调试器的工具。有许多 Python 调试器可供选择,每一个都有自己的优点和缺点。有些涵盖 Python 的特定领域,选择专门化,而有些是通用调试工具,具有与其他调试程序类似的功能。

Python 其实有自己的调试工具,叫做pdb

从技术上来说,pdb是一个可以导入使用的模块。这个模块让你进入你的程序,一行一行地检查它们,看看它们是否正常工作。

还记得我们前面的例子吗,使用 print()语句来检查我们的 stats 随机值是否被正确分配?使用 pdb 调试器模块,您可以获得相同的结果,而不必编写所有这些print()语句。

您可以在 Python 的文档网站上了解有关 Python 调试器 pdb 模块的更多信息,只需确保您正在查看的文档版本与您计算机上安装的 Python 版本相匹配即可。以下是 Python 3.6 的链接,例如:

https://docs.python.org/3.6/library/pdb.html

Python 3.7 以断点()命令的形式对 pdb 模块进行了一点升级:

https://docs.python.org/3.7/library/pdb.html

与日志记录一样,您应该学习调试,并从现在开始学习基础知识,然后,当您创建更复杂的程序时,就可以更轻松地使用您最终选择的程序。现在,我会坚持使用pdb

处理错误的最后一个技巧

如果我以前没有说过,我想留给你最后一个发现和处理代码中错误的技巧:使用注释。

那到底是什么意思?

这个概念很简单:如果您怀疑某段代码给您带来了问题,使用注释(#)使代码行对 Python 不可见,然后运行您的代码,看看问题是否仍然存在。如果没有,你已经发现了你的问题;如果问题仍然存在,继续下一段代码。

对于更复杂的结构,如 if 块,使用多行注释(“' '”)来注释掉整个部分。例如:

"""
IF
code
code
code
"""

会注释掉三引号(“”)之间的代码。

这是所有级别的编码人员都使用的一种常见做法。只是不要忘记在检查和/或修复代码后取消注释!

在这一集里!

你能相信我们已经走了这么远吗?离我们结束超级英雄的冒险只剩一章了!

超级!太棒了!惊人的!太神奇了!壮观!

轰!砰!嘭!索克-欧!

这一章是关于错误的:发现错误、修复错误、记录错误和调试错误。以下是这些主题的一些亮点,您可以在闲暇时回顾一下。

然后,就到了最后一章!

  • Python 中的三种错误类型是:语法错误、逻辑错误和异常。

  • 语法错误类似于拼写错误或语法错误;它们通常是致命的,会导致您的代码无法执行。

  • 当您的编程逻辑中存在缺陷时,就会出现逻辑错误。它们并不总是导致明显的错误,而是经常导致程序行为异常而不是崩溃。

  • 异常并不总是导致错误,尽管抛出了异常,程序仍然可以运行。

  • 有许多类型的内置异常,包括 ValueError 和 NameError。

  • 除了内置异常,我们还可以使用 raise 和 assert 创建自己的异常。

  • Try-except-else-finally 块允许您指定在遇到某些标准(或错误类型)时会发生什么,从而使您能够更好地控制错误的处理。

  • 异常处理是处理异常错误的过程。

  • 日志记录允许您跟踪代码中的错误、警告、调试信息和事件。您可以将这些日志文件保存到一个单独的文件中供以后使用。

  • 您可以使用日志模块来帮助记录。

  • Python 中有许多工具可以帮助您调试——或者找到错误并修复它们。

  • Python 的内置调试器是模块 pdb。

  • 您可以使用单行注释和多行注释来注释掉可能会(也可能不会)导致程序错误的代码块。然后您可以测试您的代码,看看这些注释掉的部分是否是罪魁祸首。

十四、Python 职业生涯

年轻的英雄,这是一个漫长的旅程。我们战胜了许多敌人——像杰克·汉默和邪恶的阿尔杰布罗这样邪恶的恶棍。我们通读了这本神秘的大部头,获得了洞察力和智慧,这使我们能够将我们的力量提升到前所未有的高度。我们在谈论珠穆朗玛峰类型的高度。

或者,至少,操场上那个很高的滑梯的顶部。

不管怎样,当我们第一次一起开始这次冒险的时候——这确实是一次冒险——你只是一个跟班,你的超级紧身衣上有芥末污渍,穿着皱巴巴的斗篷。你的面具,虽然色彩鲜艳,却勉强遮住了你的脸。

但是看看你现在!一个全面发展的英雄,充满了惊人的力量。你可以创建自己的程序,编写视频游戏,入侵(合乎道德的)计算机,完成伟大的数学壮举,随机生成统计数据,等等。

你已经从初出茅庐的英雄变成了超级英雄;从学生到…嗯,更好的学生。

但最重要的是,你已经从读者变成了程序员。我的朋友,这就是这本书的目的。

然而,即使你站在这个伟大的悬崖上,舒适地呆在你精心布置的超级英雄巢穴里,练习你新发现的力量和知识,你也绝不能休息。世界是一个不断变化的景观,技术也是如此。Python 也是一只不断进化的野兽,看不到尽头。

正因为如此,你必须继续练习你已经掌握的知识,直到它变得像第二语言一样。你需要用代码做梦!然后,走出去,学习更多的语言,做更多的梦!

Python 还有很多东西等待你去发现和成长。这本书只是冰山一角。你在书本上学不到的实际的、真实世界的经验正等着你。Python 的更新版本在等着你。

或许还有其他语言。

我鼓励你拓展业务,永远不要满足于自己的知识。看看其他语言。考虑学习一些 Perl,它非常类似于 Python,应该很容易上手。Ruby on Rails 和 PHP 也是很好的下一代语言,尤其是如果您希望扩展到 web 应用编程的话。

C 和 C++ 稍微难一点,但是非常值得努力学习,即使你只是学习基础。当你在做的时候,HTML、JavaScript 和 JSON 都是你应该添加到你的简历和技能集中的便利工具。

说到简历,这最后一章有一个真正的目的:让你为真实的编程世界做好准备。无论你是 13 岁还是 14 岁,迟早你都需要决定你希望在职业道路上朝着什么方向前进;知道你现在有哪些选择可以帮助指导你未来的学习道路。

例如,如果你决定从事游戏编程,继续学习 Pygame 和玩 Scratch 肯定会有帮助。添加像 C、JAVA 和 C++ 这样的语言是一个明确的要求——尤其是 C++。

在这一章中,我们将看看所有当前和未来的职业选择,以帮助你开始思考你成年后想做什么。我们还会看看常见的面试问题,针对那些已经成年并需要开始支付这些账单的人!

毕竟,你不能指望靠一份超级英雄的薪水就能成功…

我们还将更新我们对最佳编程实践的记忆,以便我们继续编写好的代码,并在获得它们后保住我们的工作。我再怎么强调好的编码原则的重要性也不为过。世界的未来取决于此!

说到未来(没错,我就是塞格王!),我们将看看 Python 作为一种语言的未来。我们将讨论它在虚拟现实(VR)、增强现实(AR)、人工智能(AI)以及一系列其他缩写中的作用,这些缩写让我们在说它们时听起来既时髦又酷。

最后,我们将用 Python 术语备忘单来结束这一章,并回答一些关于 Python 和编程的常见问题。

这是一条漫长的路,没有理由再走下去了。穿上你的超级英雄靴子,系好鞋带!是时候结束这段旅程了。

超级英雄风格!

使用 Python

当你拿起这本书的时候,你的脑海中可能有也可能没有职业道路,这没关系;许多人不知道他们长大后想做什么,直到他们过了成年的年龄!

无论你是否知道自己想成为什么,或者想从事什么职业,有一件事是肯定的:你关心那是什么。你投资了这本书,更重要的是,投资了你自己,这就是证据。你花时间阅读这些页面并尝试代码,这比你这个年龄的许多人迄今所做的都要多。对你有好处!

下一步是弄清楚你想用你获得的知识做什么。最有可能的是,你会想继续做一名 Python 开发人员,而不考虑你可能学习的领域或其他语言和技能。

你在职业生涯中所做的一些事情将取决于你选择之外的因素。你遇到的人,你生活的地方,和可获得的工作将会一直影响你的道路走向。你可能开始认为你会成为一名视频游戏程序员,在一家视频游戏开发公司实习,担任游戏测试员,以获得一些经验,并转向这条道路。谁知道呢——这是生活冒险的一部分!

这并不意味着你不能瞄准某个目标,甚至坚持下去。要知道,无论你的计划多么用心良苦,有时你可能会发现自己身处出乎意料的地方,这没关系。

除此之外,知道自己想去哪里是件好事。因此,记住这一点,让我们看看当你发展成为兼职超级英雄、全职程序员时,一些可能的职业选择。

Python 的职业道路

本节列出的职业道路没有任何特定的顺序;没有一个比其他的更好,尽管你可能会发现一些地区的工资比其他地区高。我们不会专注于此。我坚信做自己喜欢的事。如果你那样做了,成功就会随之而来。

这份清单绝不是决定性的;有相当多的职业可以选择,但这些是目前最常见的。

β系数测定器

测试人员是软件开发者世界的无名英雄。他们测试程序和软件,并从技术角度和用户体验角度找出哪些可行,哪些不可行。在某些情况下,你可能会被要求专门测试某个程序的某个特性或方面;在其他情况下,您可能需要检查一切。

编程知识对这个角色很重要,但不是最重要的。从编程语言的角度来看,我已经测试了许多我没有实际经验的程序;我理解这些概念和事情是如何运作的,这很好地服务于它的目的。

当然,如果你懂这门语言,并能准确指出代码中的问题,那就更好了,你可能会更容易找到工作。

很可能,你已经测试过软件,但可能还没有完全意识到。如果你是一个狂热的视频游戏玩家或手机游戏爱好者,你经常会在测试版向大众发布之前尝试它。虽然这与付费演出不太一样,但也有好处,比如免费的软件和/或硬件。

代码调试器/错误定位器

这听起来可能类似于 beta 测试人员,但在大多数情况下,它实际上更复杂一些。你的任务是:找出不可靠的、糟糕的代码,并报告如何修复它——或者自己修复,这取决于工作。

如果你是那种喜欢花几个小时试图解决程序有什么问题的人,或者喜欢把东西拆开的人,这可能是你一个很好的职业选择;至少,这是一项很好的技能,不管你的职业道路会把你带到哪里。

请记住,你将会浏览其他人的代码,有时还会浏览多个人的代码。希望这些人能够很好地记录文档并遵循标准的指导方针,但是你永远不知道你会遇到什么。

尽管如此,这仍然是一种保持领先的好方法,如果你成为一名软件开发人员或创建自己的应用,善于发现程序中的错误将会派上用场。

数据科学家

如果你擅长统计、数字和研究,你可能会考虑进入数据科学领域。Python 在数据科学的世界里是巨大的,这是统计学和机器学习技术的混合物。

得益于其庞大的数学和数据可视化工具库(如 matplotlib 和 NumPy),Python 程序员在数据科学职业方面处于领先地位。在这一行中,您将使用图表和其他工具来帮助组织、解释和显示各种行业和应用的数据集。

您开发的算法和您对数据的解释有助于组织或企业做出关键决策。在这条职业道路上,你需要一个善于分析的大脑,良好的数学技能,当然,还需要一点编程知识,但对于那些喜欢弄清楚信息真正含义的人来说,这肯定是一个有回报的领域!

软件开发人员/软件工程师

当成为一名软件开发人员时,有很多选择。这可能是你在考虑自己在大计划中的位置时首先想到的角色。

软件开发人员创造了大量的软件,包括生产力应用(如微软 Office)到音乐创作程序以及你能想到的几乎任何东西。只要看一眼你电脑上的应用,你就会对这个范围有多广有所了解。

如果你决定成为一名软件开发人员或软件工程师,请记住,你会想尽可能多地学习 Python 和其他语言;了解其他语言和框架不会有什么坏处,另外,一旦你了解 Python,学习第二种或第三种编码语言会变得容易得多,因为许多逻辑和结构在不同语言之间是相同的;这主要是学习新的语法和编程风格的问题(例如,不是每种语言都使用缩进)。

视频游戏程序员

虽然这个职业在技术上与软件开发人员属于同一条道路,但我想我应该特别提到它。作为一个电子游戏的狂热爱好者——毕竟,这是我最初进入编程的原因——如果我不把它作为一个独立的职业选择,那我就失职了。

在过去的十年里,视频游戏的发展真的很繁荣。事实上,当我在大学的时候,只有少数几个学院——大部分是专业——提供游戏开发的课程,更不用说学位了。事实上,我的大学只开设了一门这样的课程——而且一年只有一次!

当然,我们过去都是在巨石上凿我们的代码,那时我们鼻子里戴着骨头,但是仍然…

如果你想为主流主机开发,你需要知道的不仅仅是 Python 和 Pygame。事实上,虽然 Python 肯定会帮助您理解所需的一些逻辑,但您确实需要扩展到 C++ 并涉足一些 C 和 JAVA。

如果你选择走非主机游戏或 PC 游戏的路线,你可能会有更多的选择,但实际上,在撰写本文时,C++ 才是正确的选择。

移动开发

虽然 Python 不是您可能想到的第一种移动开发语言,但是您确实可以使用该语言来创建应用和/或与其他更擅长移动应用开发的语言结合使用。

移动应用包括您在手机或平板电脑上使用的任何应用。这可能是游戏、messenger 应用、新闻阅读器应用、银行软件,甚至是网站的移动版本——清单还在继续。

如果你选择了这个重要而巨大的市场,你将会很好地学习真正的移动开发语言:C#或 Objective-C、C++、JAVA、Swift,甚至 HTML5。为了简单起见,您可能希望从 HTML5 开始,因为它可能比列表中的其他语言更容易学习。你也可以使用 HTML5 进行 web 开发,所以如果你发现移动应用开发不适合你,这是一个非常方便的工具。

当然,C++、C 和 JAVA 也会为你打开其他的大门,但是它们学习起来稍微复杂一些,所以这完全取决于你的时间框架和需求。

无论哪种方式,只要知道您可以使用 Python 进行移动开发,即使它的这种用途并不广为人知。

网络开发和网络应用

如果您想创建基于 web 的应用,Python 当然可以在这方面提供帮助。事实上,Python 真正的优势之一是它的一系列强大的 web 框架,比如 Django 和 Flask。这些框架充当某种蓝图或框架,让您快速部署应用的“骨骼”,节省您大量的设置和编码时间。基本上,它们为您创建了 web 应用中的基础,因此您不必重新发明轮子。

将 Python 和 web 框架与 HTML5 以及一点 JavaScript 结合起来,你将成为互联网世界中不可忽视的力量。例如,Google、YouTube 和 Yahoo 的平台都依赖于 Python。如果这还不能告诉你 Python 有多好,我不知道还有什么能告诉你!

系统管理员

而系统管理员(或者系统管理员,如果你敢!)是一群有趣的人,他们也是任何组织中非常必要的一部分。您可能已经猜到了,Python 非常擅长帮助系统管理员完成工作。

系统管理员使用 Python 来创建工具和工具,帮助他们管理计算机系统、控制操作系统和处理网络任务。

它还允许您创建自己的服务器和客户端、消息传递系统等等。Python 是迄今为止系统管理员最好的朋友。

那个,还有猫,出于某种原因…

研究、教学等等

Python 也是一个很好的研究工具,正如数据科学家一节所提到的。它有如此多的库和工具来处理复杂的方程和数据集,难怪 NASA 如此依赖这种语言。

更重要的是,在学校或大学环境中教授 Python 始终是一种谋生的好方法,同时也是向后代传授知识的好方法。它很容易学习,而且作为副产品,也很容易教,这是计算机科学课程要求中非常常见的第一步。

谁知道呢…如果你教得足够多,也许有一天你可以写一本关于它的书。

你知道吗…算了吧。把这本书留给我写;我有狗要喂!

常见的 Python 面试问题

对于一些正在阅读这本书的人来说,你不必担心在面试中会被问到什么样的问题;对于其他人来说,这将是一个非常现实的问题,宜早不宜迟。无论哪种方式,无论你是准备进入职场,还是还太年轻而不能考虑这样的事情,我们建议你花时间学习和思考本节中常见的 Python 面试问题列表。

虽然这本书涵盖了很多这样的主题,但还有很多没有;记住,这是一本初学者的书,旨在教你开始用 Python 编程所需要的东西。这并不意味着让你全副武装地去工作。

如果有任何术语或想法没有意义,我们建议您使用谷歌搜索,在其他书籍中查找,并尽可能多地学习。这些问题和答案不仅仅是为了帮助你通过作弊找到工作,因为你擅长记忆;事实上,这些问题是常见的面试问题,因为它们回避的概念是重要的编程原则。

因此,知道这些问题的答案——进一步,通过学习和实践真正理解它们——不仅会帮助你在准备好的时候找到工作,还会帮助你在那份工作上保持甚至茁壮成长!

你能告诉我 Python 的一些关键特性吗?

这是一个看似简单的问题。面试官想看看你对 Python 的了解程度,你对这门语言有多感兴趣,以及你对它的通用特性了解多少。虽然您可以指出很多,但最常见的是:

  • Python 是一种解释型语言,这意味着它不需要像某些其他语言一样在运行之前进行编译。

  • Python 是一种多用途语言,能够用于广泛的领域,包括数据科学、道德黑客、系统管理、web 开发、移动应用开发、视频游戏编程、科学建模等等。

  • Python 可读性强,简单易学,但功能强大。它是一种面向对象的语言,是动态类型的(这意味着不需要定义你声明的变量的数据类型;Python 在很大程度上可以检测出您想要的数据类型)。

元组和列表的区别是什么

我们在前面的章节中讨论过这个问题,答案非常简单:元组是不可变的,这意味着它们的值不能改变。同时,列表是可变的,这意味着你可以改变它们的值。另一个区别是元组需要圆括号(),而列表使用方括号[]。最后,虽然人们可能不会注意到,但从技术上讲,列表比元组慢。

什么是继承?

我们在处理对象和类的章节中讨论了继承的概念。您可能还记得,类遵循层次结构,类似于父子关系。当我们有一个父类或者超类时,这个父类的子类继承了父类的属性和方法。

记住:类和对象——面向对象编程(OOP)的一个关键特性——都是关于代码可重用性的。一个子类可以从一个父类或多个父类继承,从而具有很大的灵活性和很高的编码效率。

在 Python 中如何生成随机值?

我们在本书中经常用到的一个重要模块是random。这对于在超级英雄生成器程序中创建我们英雄统计的随机值至关重要,也用于随机选择超级英雄的名字和能力。

要使用它,我们首先必须导入它:

import random

然后将其应用到我们的代码中。例如,我们可以写:

import random

a = random.randint(1, 10)

print(a)

这将在变量a中存储一个 1 到 10 之间的随机值,然后打印出来。

如何用 Python 创建列表、元组和字典

这似乎是一个简单的问题,但是如果程序员不得不当场做的话,这可能会难倒他们,所以练习创建每一个,并知道什么时候使用它们,以便它成为你的第二天性。

答案是:

myList = ['James', 'Mike', 'Spinach Man', 'Mister Kung Food']

myTuple = ('James', 'Mike', 'Spinach Man', 'Mister Kung Food')

myDict = {'Writer' : 'James Payne', 'Student' : 'YourName'}

局部变量和全局变量有什么区别?

局部变量应该在函数中使用;也就是说,我们在函数内部创建变量。如果变量是在函数之外定义的,它就被认为是全局变量。

Python 提供了哪些不同的数据类型?

Python 中总共有五种基本数据类型:数字、字符串、列表、元组和字典。

什么是图形用户界面?什么 Python 库最适合 GUI 开发?

这个由两部分组成的问题有一个简单的答案。首先,GUI 代表图形用户界面,它允许你在程序中加入按钮、标签、文本框、复选框、单选按钮等等。

Python 用于 GUI 开发的默认库被称为 Tkinter。

如何用 Python 打开一个文件?

这是我们在本书中涉及的另一个主题。您可能还记得,我们使用 open()函数打开一个文件。我们首先指定文件的名称和位置(如果文件位于根目录之外),然后指定打开文件的模式。例如:

myFile = open("test.py', 'w')

以写模式打开位于根目录的文件test.py

你如何列出一个模块的功能?

你可能会被问到的另一个常见的面试问题是,如何查看给定模块中的函数列表。为此,我们使用dir()方法:

import random

print dir(random)

使用help()也有助于查看模块中的文档。

其他 Python 面试问题

你永远不知道在面试中你会被问到什么类型的 Python 特有的问题,所以确保你在面试前做了充分的准备。这里包括的问题很常见,但是你可能会被问到更多的问题。

此外,您很可能会被要求回答一些特定于代码的问题,或者被要求编写代码来临时执行一些特定的功能。准备写基础,知道最常见的内置和函数。

准备工作面试的一个很好的方法是研究公司和你将在那里做的节目类型。例如,如果公司开发 web 应用,你提前知道你会被问到关于 web 框架的问题。

最后,随时准备回答与 Python 或编程无关的问题——这些问题也会被问到。在面试过程中,职业目标、过去的经历、性格问题以及总体态度/态度都会被考虑在内,所以一定不要忽视基本的面试准备。

清洁你的耳朵后面…你未来的老板可能会检查他们的背后!

最佳编程实践

虽然大部分编码是个人喜好,但当你进入职场时,总有你必须遵循的标准。我们讨论了良好和适当的文档的重要性;这一部分是关于要遵循的最佳编程实践。

本节中的提示将帮助您成为更好的程序员,使您更高效,避免常见的陷阱,并减少您的编码错误。到目前为止,这还不是一个完整的列表,但是它应该让你像超级英雄一样走上编码之路!

遵循风格指南

在他无限的智慧中,Python 的发明者创造了所谓的风格指南。就像 Python 本身一样,这份风格指南被称为 PEP——或 Python 增强建议——它是 Python 中广泛主题的建议列表。它涵盖了从废弃的(删除的)模块到风格指南,再到语言进化指南的所有内容。

从字面上看,有许多 pep。例如,风格指南是 PEP 8,最初是由我们伟大的领导者 Guido Van Rossum、Barry Warsaw 和 Nick Coghlan 在 2001 年创建的。

它涵盖了如何布局你的代码,是否使用制表符或空格缩进,你的代码的最大行长度,使用字符串引号,等等。

大多数雇佣你的工作都希望你熟悉这个特殊的 PEP,尤其是包含缩进和命名约定的部分。这不仅会帮助你的同事审查和处理你的代码,而且 PEP 风格指南也会帮助你编写更好、更有效和防错的代码。

你可以在 Python 找到 PEP 8。org 网址: www.python.org/dev/peps/pep-0008/

您可以在以下网址找到所有 pep 的列表:

www.python.org/dev/peps/

作为一个例子,下面是 PEP 8 关于命名约定的说明:

类:名称中的第一个和第二个单词(以及任何其他单词)使用大写字母。比如:VillainType或者MutateClass

变量、函数、方法、模块和包:使用由下划线分隔的小写单词。比如:我的 _ 英雄 _ 名或者我的 _ 恶棍 _ 名。

如果它坏了,修好它(现在,而不是以后)

通常,当我们在一个项目上取得很大进展时,我们希望继续向前推进。在办公室环境中尤其如此,当最后期限的压力迫在眉睫,你开始感到时间紧迫,甚至被骚扰以完成你的代码部分并继续下一部分。

然而,这种心态可能会成为一个大问题。虽然我们可能会试图忽略代码中的小错误,并认为我们可以回头修复它们,但事实是,这种思考过程更多的时候是一个陷阱,而不是一种帮助。

这里或那里的错误是意料之中的,但是,就像雪山上的雪崩一样,它们可以很快开始堆积并摧毁它们所经之处的一切。错误往往会导致其他错误,形成多米诺骨牌效应。如果一部分代码不能正常工作或者给你带来错误,它会使其他部分表现异常。更糟糕的是,那些受影响的部分甚至可能不会给出警告或错误,从而导致更大的问题。

这里的教训很简单:经常测试你的代码。如果你发现一个 bug,立即修复它,除非问题得到解决,否则不要继续工作。你以后会感谢我的,相信我!

文档就是一切

我们在书中多次提到这种想法,但在这里值得重复:永远,永远,记录你的代码。清晰的文档是项目成功的关键——这包括其初始版本,以及随后的任何版本。

众所周知,Python 程序可以包含数千行代码。甚至几百万。你读过别人的信件或电子邮件吗?在最好的情况下,人们并不总是清楚的,即使他们和你说同样的语言。Python 也不例外;虽然每个代码(至少应该)都试图坚持传统的命名约定和代码结构,但事实是,许多编码人员都是自学成才的。

随着时间的推移,我们也会变得懒惰和自负;我们假设任何看我们代码的人都会理解我们的意图。更糟糕的是,我们认为我们会记得几年前我们试图做的事情。

虽然记录你的代码可能会多花一点时间,但从长远来看,它会节省你很多时间。不管这样做是因为它减少了你花在追踪 bug 和代码错误上的时间,还是因为你可以快速重用部分代码,文档可能是最重要的——在我的书中(这毕竟是我的书),你可以遵循的最佳实践。

当我们说文档时,它不仅仅包括#注释或“多行注释”;它还包括正确的 docstring 用法。

当你成为一名专业的程序员时,也有一些工具可供你使用,比如 Sphinx 和 reStructuredText。但是现在,从基础开始,练习记录你写的每一段代码。

使用代码库和包

使用 Python 的最大卖点之一是,您可以访问由 Python 开发人员社区创建和测试的庞大的 Python 包库。当您在自己的项目中工作时,这些代码和函数可以为您节省大量的时间、错误和痛苦。俗话说,为什么要重新发明轮子?

您可以在位于 https://pypi.org 的 Python 包索引(PyPi)存储库中找到要使用的包。目前有 155,000 个项目上市,用户近 300,000。

如果您不确定正在寻找什么或正在寻找灵感,您可以搜索项目、浏览项目或查看趋势项目列表。

除了寻找对你的程序有帮助的包之外,你还可以在 PyPi 网站上学习如何打包——以及托管——你自己的包,以便他人测试和使用。

我强烈建议你经常访问这个站点,看看 Python 社区中的其他人都在做些什么。

您可能记得我们在本书中使用 pip 安装了几个包;这是那些包来自的存储库。

经常测试

仅仅因为它需要被重申,我将用另外一段或两段来说:测试你的代码。经常测试。

每当您进行新的重大更改或添加另一部分时,请测试前面的代码。即使是像 if 块或小循环这样简单的事情。如果您有一部分代码依赖于决策或条件语句,请确保测试每个可能的答案。

例如,如果你有一个 if 块,然后说“如果是,那么 X,如果不是,那么 Y,否则 z”,确保你执行这些条件中的每一个。在你的测试中要彻底,如上所述,如果你发现警告或错误,就要修正。

然后,一旦你修复它,再次测试。

选择一边:缩进或空格

这又回到了我们关于风格指南和 PEP 建议的对话;编写代码时,一定要选择是使用空格缩进还是制表符。

那就坚持这个决定。

我亲眼目睹了关于使用哪种方法的争论,最终,我会说这样的话激怒一半的 Python 用户:没关系,只要你始终如一地使用你的选项。

除了个人偏好和 PEP 指导方针,请记住,你工作的任何组织都有自己的风格指导方针,这些指导方针将优先于其他任何东西——个人偏好或其他。

但是同样,在编码时,总是使用相同的间距/制表符约定。

班级很棒,但是并不是所有的事情都需要成为一个班级

任何时候你用 Python 或者任何语言编写任何结构或者东西的时候,总是要考虑它是否是你所做的最好的服务。例如,类在可重用性方面非常好,但函数也是如此。模块也是如此。

说到底,你真正的工作是让一切尽可能简单。如果你这样做了,那么你将会实现我们在本书中多次提到的目标:可重用的代码,减少错误,高效的代码。

保持事物简单的另一个好处是,它使一切更具可读性,这一点的重要性不能被夸大。东西越容易阅读,你和你的同事就越容易追踪问题或添加代码段。

这是使用太多类和模块的负面影响的一部分;虽然它们在许多方面都很棒,但它们往往会破坏 Pythonic 代码的可读性。

使用它们,无论如何;只要确保它们是必要的,并且是最简单的方法来完成你想要达到的目标。

Python 的未来

目前,Python 可以说是这个星球上最常用的编程语言。这一趋势已经持续了相当长一段时间,似乎没有放缓。这种语言简单易学、功能强大且灵活,在可预见的未来,它失宠的可能性非常小。

有几个领域预计会随着 Python 的发展而迅速发展。在某种程度上,这是由于这些特定的利基或行业越来越受欢迎。对于其他人来说,这是因为 Python 在这个领域表现出色。

这方面的一个例子是数据科学、研究和科学编程应用。这种语言在这个领域已经是一个强大的语言,作为数据科学的入门工具,它只会继续发展。

推动 Python 发展的另一个因素是有许多公司基于 Python 2 构建应用。随着 Python 3 的稳定,这些公司开始更新和移植他们的代码到 Python 3,这比换一套全新的代码要简单得多。

当然,Python 并不是无懈可击的。Python 在某些领域确实需要发展。其中之一就是移动开发。然而,不要回避这个领域,你当然可以期待 Python 社区和 Python 创作者挺身而出,确保在移动应用开发和帮助你解决这个领域的工具方面,Python 不会落在后面。

迫在眉睫的——或者现在就敲门,这取决于你在编程研究和技术观点方面的进展——是高科技领域,如人工智能(AI)、虚拟现实(VR)、增强现实(AR)和不断增长的物联网(IoT)领域。智能家居和互联设备是一个快速增长的市场,可以肯定的是 Python 将成为这个市场的一部分。

最终,Python 的学习曲线和易用性使它成为一种在未来几十年将被广泛使用的语言。为什么呢?简单:如果你拥有一家公司,你可以雇佣一个能够快速上手编写 Python 代码的人。结合它的灵活性,社区开发的大量 Python 包,以及我们在本书中讨论的所有其他伟大的东西,我确信 Python 仍然是程序员的发电站。

你也应该如此。

Python 术语

Python 中讨论了很多术语。这本书尽管可能很全面,但并没有涵盖所有的内容。为了帮助总结本书中的数据,并教你一些新的术语,我们包括了这一节来帮助定义一些你作为程序员继续开发时可能会遇到的更常见的 Python 术语。

自变量:你赋给一个函数的值。也称为参数。

赋值:给变量、列表、字典、元组或者其他对象赋值。

布尔:等于TrueFalse的值。

:你可以把一个class想象成一个object的蓝图。有超类——或父类——和子类。子类可以继承父类的特征——方法和属性。使用这些蓝图,你可以基于一个或多个类快速创建对象。

注释:一个comment用来帮助记录——或者解释——一段代码的用途。您可以使用一个#后跟一个空格,然后是一个single-line comment的文本进行注释,如下所示:

# This is a comment.

当 Python 看到#符号时,它会忽略该行空白后面的所有内容,允许您给自己或其他程序员留下注释。如果你需要更多的空间,你可以在后面的每一行注释中继续使用#或者你可以使用'''或者"""进行多行注释。以下是一个多行注释的示例:

'''
Here is a comment.
Here is another.
Here is more!
'''

条件语句:根据是否满足某个条件来决定是否执行的语句。

def : def用于define——或者创建——一个function。更多信息请参见术语函数。

字典:一个dictionary是由一个或多个key-value对组成的数据类型。在这种情况下,每个key对应一个value。字典的关键部分是immutable,意思是不能改变。字典中的值可以是任何类型——数字、字符串或其他类型,并且可以改变。我们这样定义字典:

example_dict{'Name' : 'Paul', 'Age': '22'}

这会给字典分配两个items。第一个键值是Name : Paul,其中Name是键,Paul是值。第二个键是Age,其值为22

docstring :文档字符串;嵌入到 Python 程序、模块或函数中的一段文档。

浮点:十进制数,如 2.5 或 102.19。

函数:一个function是你可以在你的程序中调用的代码。我们通常使用函数来保存我们打算多次使用的代码。

下面是我们如何define一个函数:

def name_of_function(parameters):
      # Here is where your code would go. For example:
      print("Look, I'm a function!")

为了call这个函数,我们可以输入:

name_of_function()

不可变:如果某个东西是immutable,那就意味着你不能改变它的值。

导入:将一个库加载到你的程序中。

整数:整数,比如 1400,20000,甚至-50000。

iterable:aloop的别称。

len :函数len()用于统计一个对象的长度,比如variablelist中的项目等等。如果在列表中使用,它将计算项目或元素的数量。如果用在string上,它会计算字符串中的字符数。以下是一些例子:

a  = "This is my variable"
some_list = [1,2,3,4,5]

len(a)
len(some_list)

这将导致:

19
5

注意

len()也计算空格。

List : Lists是一种 Python 数据类型,存储任意类型的有序值组。与tuples不同,列表是mutable,这意味着它们保存的值可以改变。

要创建列表,您可以键入以下内容:

my_list = [0,1,2,3,4,5]
my_other_list = ['James', 'Super Taco', 'Not So Super Taco', 'Regular Taco Man']

循环:一个loop被用来iterate——或者重复——一段给定的代码,重复的次数取决于一组标准。有一个for循环,无论你告诉它多少次,它都会重复;还有一个while循环,只要条件是TRUE,它就会重复。

一个for循环的例子:

for i in range(0, 5):
      print(i + 1)

这将导致:

1
2
3
4
5

while循环示例:

while a == 4:
      print(" a equals 4! Yay!")

方法:属于一个对象的函数。

可变:某个mutable的东西可以改变它的值。

object :你用一个类的蓝图创建的东西。

参数:参数的另一个名称(尽管有些人会反对这种比较)。

print():print()函数让我们在用户的屏幕上显示或输出一些东西:

print("Hello Universe!")

会导致:

Hello Universe!

字符串:一个string是由任何字母、数字、空白或特殊字符组成的数据类型。

语法错误:当你输入了错误的文本,拼错了一部分代码,或者犯了语法错误时遇到的错误。

回溯:导致错误的函数调用的顺序列表。

元组 : A tuple是一种数据类型,存储任何类型的值的有序集合。与列表不同,它们是不可变的,它们的值不能改变。

您可以使用类似以下代码创建元组:

my_tuple = ('El Taco Diablo', 'Tiny Monster', 'Guy Focal')
my_other_tuple = ('0', '1', '2', '3', '4')

变量 : A variable是存储单个值的数据类型。该值可以是数字、字符、句子等等。它们还可以包含列表、字典,甚至函数。

要创建变量,可以使用赋值运算符:

a = 12
b = "Snap, The Cereal Killer!"