笨办法学 Python3 第五版(预览)(三)

原文:Learn Python the Hard Way, 5th Edition (Early Release)

译者:飞龙

协议:CC BY-NC-SA 4.0

练习 30:假如

这是你将要输入的下一个 Python 脚本,它向你介绍了if语句。输入这个代码,确保它能够完美运行,然后我们将看看你的练习是否有所收获。

列表 30.1:ex30.py

 1   people = 202   cats = 303   dogs = 15456   if people < cats:7       print("Too many cats! The world is doomed!")89   if people > cats:
10       print("Not many cats! The world is saved!")
11
12   if people < dogs:
13       print("The world is drooled on!")
14
15   if people > dogs:
16       print("The world is dry!")
17
18
19   dogs += 5
20
21   if people >= dogs:
22       print("People are greater than or equal to dogs.")
23
24   if people <= dogs:
25       print("People are less than or equal to dogs.")
26
27
28   if people == dogs:
29       print("People are dogs.")

你应该看到的内容

1   Too many cats! The world is doomed!
2   The world is dry!
3   People are greater than or equal to dogs.
4   People are less than or equal to dogs.
5   People are dogs.
dis()

在接下来的几个练习中,我希望你运行dis()在你正在学习的一些代码上,以便更深入地了解它是如何工作的:

1   from dis import dis
2
3   dis('''
4   if people < cats:
5       print("Too many cats! The world is doomed!")
6   ''')

是你在编程时通常会做的事情。我只是希望你在这里这样做,以便为你理解正在发生的事情提供另一种可能的方式。如果dis()并没有真正帮助你更好地理解代码,那么随意这样做并忘记它。

要研究这个问题,只需将 Python 代码放在这个dis()输出旁边,然后尝试识别与字节码匹配的 Python 代码行。

练习题

在这个练习中,试着猜测if语句是什么以及它的作用是什么。在继续下一个练习之前,尝试用自己的话回答这些问题:

  1. 你认为if对下面的代码有什么影响?

  2. 为什么if下面的代码需要缩进四个空格?

  3. 如果没有缩进会发生什么?

  4. 你能否在if语句中放入来自练习 28 的其他布尔表达式?试一试。

  5. 如果你改变peoplecatsdogs的初始值会发生什么?

常见学生问题

+=是什么意思? 代码x += 1x = x + 1相同,但输入更少。你可以称之为“递增运算符”。对于-=和许多其他表达式,你以后会学到的也是一样。

练习 31:否则和如果

在上一个练习中,你解决了一些if 语句,然后试图猜测它们是什么以及它们如何工作。在学习更多之前,我将通过回答你在学习练习中提出的问题来解释一切。你做了学习练习,对吧?

  1. 你认为if对其下面的代码有什么影响?if 语句在代码中创建了所谓的“分支”。这有点像那些选择你自己冒险的书,如果你做出一个选择,就会被要求翻到一页,如果你选择另一条路,就会翻到另一页。if 语句告诉你的脚本,“如果这个布尔表达式为真,则运行其下的代码;否则跳过它。”

  2. 为什么if下面的代码需要缩进四个空格?在一行的末尾加上冒号是告诉 Python 你将创建一个新的代码“块”,然后缩进四个空格告诉 Python 哪些代码行在该块中。这与你在本书的前半部分创建函数时所做的事情完全相同。

  3. 如果没有缩进会发生什么?如果没有缩进,你很可能会产生 Python 错误。Python 希望你在以:(冒号)结尾的行之后缩进一些东西。

  4. 你能把练习 28 中的其他布尔表达式放在if 语句中吗?试试看。是的,你可以,而且它们可以尽可能复杂,尽管非常复杂的东西通常是不好的风格。

  5. 如果更改peoplecatsdogs的初始值会发生什么?因为你正在比较数字,如果更改数字,不同的if 语句将评估为True,并且其下的代码块将运行。回去放入不同的数字,看看你是否能在脑海中弄清楚哪些代码块将运行。

将我的答案与你的答案进行比较,并确保你真正理解代码“块”的概念。这对于你做下一个练习很重要,其中你将编写所有可以使用的if 语句的部分。

将这个输入并使其工作。

列表 31.1:ex31.py

 1   people = 302   cars = 403   trucks = 15456   if cars > people:7       print("We should take the cars.")8   elif cars < people:9       print("We should not take the cars.")
10   else:
11       print("We can't decide.")
12
13   if trucks > cars:
14       print("That's too many trucks.")
15   elif trucks < cars:
16       print("Maybe we could take the trucks.")
17   else:
18       print("We still can't decide.")
19
20   if people > trucks:
21       print("Alright, let's just take the trucks.")
22   else:
23       print("Fine, let's stay home then.")

你应该看到什么

1   We should take the cars.
2   Maybe we could take the trucks.
3   Alright, let's just take the trucks.
dis()

我们现在到了一个dis()有点太复杂的地步。让我们只选择一个代码块来学习:

 1   from dis import dis23   dis('''4   if cars > people:5       print("We should take the cars.")6   elif cars < people:7       print("We should not take the cars.")8   else:9       print("We can't decide.")
10   ''')

我认为学习这个最好的方法是将 Python 代码放在dis()输出旁边,尝试将 Python 代码的行与其字节码匹配。如果你能做到这一点,那么你将远远领先于许多甚至不知道 Python 有dis()的 Python 程序员。

如果你搞不清楚,不要担心。这一切都是关于尽可能推动你的知识,以找到理解 Python 的新方法。

学习练习

  1. 试着猜猜elifelse在做什么。

  2. 更改carspeopletrucks的数字,然后跟踪每个if 语句,看看将打印出什么。

  3. 尝试一些更复杂的布尔表达式,比如cars > people or trucks < cars

  4. 在每行上方写出该行的英文描述。

常见学生问题

如果多个 elif 块都为 True会发生什么? Python 从顶部开始运行第一个为True的块,因此只会运行第一个。

练习 32:做决策

在这本书的前半部分,你主要只是打印出一些称为“函数”的东西,但一切基本上都是直线的。你的脚本从顶部开始运行,一直到底部结束。如果你创建了一个函数,你可以稍后运行该函数,但它仍然没有你真正需要做出决策的分支。现在你有了 ifelseelif,你可以开始编写决策性的脚本了。

在上一个脚本中,你列出了一组简单的测试,询问一些问题。在这个脚本中,你将询问用户问题,并根据他们的答案做出决定。编写这个脚本,然后多玩一下,弄清楚它的运行方式。

代码清单 32.1: ex32.py

 1   print("""You enter a dark room with two doors.2   Do you go through door #1 or door #2?""")34   door = input("> ")56   if door == "1":7       print("There's a giant bear here eating a cheese cake.")8       print("What do you do?")9       print("1\. Take the cake.")
10       print("2\. Scream at the bear.")
11
12       bear = input("> ")
13
14       if bear == "1":
15           print("The bear eats your face off. Good job!")
16       elif bear == "2":
17           print("The bear eats your legs off. Good job!")
18       else:
19           print(f"Well, doing {bear} is probably better.")
20       print("Bear runs away.")
21
22   elif door == "2":
23       print("You stare into the endless abyss at Cthulhu's retina.")
24       print("1\. Blueberries.")
25       print("2\. Yellow jacket clothespins.")
26       print("3\. Understanding revolvers yelling melodies.")
27
28       insanity = input("> ")
29
30       if insanity == "1" or insanity == "2":
31           print("Your body survives powered by a mind of jello.")
32           print("Good job!")
33       else:
34           print("The insanity rots your eyes into a pool of muck.")
35           print("Good job!")
36
37   else:
38       print("You stumble around and fall on a knife and die. Good job!")

这里的关键点是,现在你正在将if-statements放在if-statements内部作为可以运行的代码。这是非常强大的,可以用来创建“嵌套”决策,其中一个分支导致另一个分支。

确保你理解了if-statements 中嵌套if-statements 的概念。实际上,做一些练习来真正掌握它。

你应该看到的结果

这是我玩这个小冒险游戏的情况。我表现得不太好。

1   You enter a dark room with two doors.
2   Do you go through door #1 or door #2?
3   > 1
4   There's a giant bear here eating a cheese cake.
5   What do you do?
6   1\. Take the cake.
7   2\. Scream at the bear.
8   > 2
9   The bear eats your legs off. Good job!

dis()

这次没有 *dis()* It 部分,因为这段代码太复杂了,难以理解,但如果你感觉幸运的话,可以尝试一下:

 1   from dis import dis23   if door == "1":4       print("1")5       bear = input("> ")6       if bear == "1":7           print("bear 1")8       elif bear == "2":9           print("bear 2")
10       else:
11           print("bear 3")

这将产生大量需要分析的代码,但尽力而为。过一段时间会变得无聊,但也有助于理解 Python 的工作原理。再次强调,如果这让你困惑,可以先跳过,以后再尝试。

练习

  1. 制作游戏的新部分,并改变人们可以做出的决定。在游戏变得荒谬之前尽可能扩展游戏。

  2. 编写一个全新的游戏。也许你不喜欢这个,那就自己创造一个。这是你的电脑;做你想做的事情。

常见学生问题

你能用一系列 if-else 组合替换 elif 吗? 在某些情况下可以,但这取决于每个 if/else 的编写方式。这也意味着 Python 将检查每个 if-else 组合,而不像 if-elif-else 那样只检查第一个为假的条件。尝试创建一些来了解差异。

如何判断一个数字是否在一系列数字范围内? 你有两个选择:使用 0 < x < 101 <= x < 10—这是经典的表示法—或使用 x in range(1, 10)

如果我想在 if-elif-else 块中增加更多选项怎么办? 为每个可能的选择添加更多 elif 块。

练习 33:循环和列表

现在你应该能够编写一些更有趣的程序了。如果你一直在跟进,你应该意识到现在你可以将所有其他学到的东西与if-statements和布尔表达式结合起来,使你的程序做一些聪明的事情。

然而,程序也需要快速地执行重复的事情。在这个练习中,我们将使用for-loop来构建和打印各种列表。当你做这个练习时,你会开始明白它们是什么。我现在不会告诉你。你必须自己弄清楚。

在使用for-loop之前,你需要一种方法来存储循环的结果。最好的方法是使用listsLists正是它们的名字所说的:一个按照从头到尾顺序组织的东西的容器。这并不复杂;你只需要学习一种新的语法。首先,这是如何创建lists的:

1   hairs = ['brown', 'blond', 'red']
2   eyes = ['brown', 'blue', 'green']
3   weights = [1, 2, 3, 4]

你用[(左括号)开始list,这个“打开”list。然后你用逗号分隔每个你想要放入列表的项目,类似于函数参数。最后,用](右括号)结束列表以表示它的结束。然后 Python 将获取这个列表及其所有内容,并将它们分配给变量。

警告!

这就是对于不能编码的人来说变得棘手的地方。你的大脑被教导世界是平的。还记得在上一个练习中你是如何在if-statements内部放置if-statements的吗?那可能让你的大脑感到疼痛,因为大多数人不会考虑如何在“嵌套”事物内部放置事物。在编程中,嵌套结构随处可见。你会发现调用其他函数的函数,这些函数有带有列表的if-statements,列表内部还有列表。如果你看到这样的结构而无法理解,拿出一支铅笔和纸,逐步手动分解,直到你理解为止。

现在我们将使用一些for-loops来构建一些列表并将它们打印出来:

列表 33.1:ex33.py

 1   the_count = [1, 2, 3, 4, 5]2   fruits = ['apples', 'oranges', 'pears', 'apricots']3   change = [1, 'pennies', 2, 'dimes', 3, 'quarters']45   # this first kind of for-loop goes through a list6   for number in the_count:7       print(f"This is count {number}")89   # same as above
10   for fruit in fruits:
11       print(f"A fruit of type: {fruit}")
12
13   # also we can go through mixed lists too
14   for i in change:
15       print(f"I got {i}")
16
17   # we can also build lists, first start with an empty one
18   elements = []
19
20   # then use the range function to do 0 to 5 counts
21   for i in range(0, 6):
22       print(f"Adding {i} to the list.")
23       # append is a function that lists understand
24       elements.append(i)
25
26   # now we can print them out too
27   for i in elements:
28       print(f"Element was: {i}")

你应该看到的内容

 1   This is count 12   This is count 23   This is count 34   This is count 45   This is count 56   A fruit of type: apples7   A fruit of type: oranges8   A fruit of type: pears9   A fruit of type: apricots
10   I got 1
11   I got pennies
12   I got 2
13   I got dimes
14   I got 3
15   I got quarters
16   Adding 0 to the list.
17   Adding 1 to the list.
18   Adding 2 to the list.
19   Adding 3 to the list.
20   Adding 4 to the list.
21   Adding 5 to the list.
22   Element was: 0
23   Element was: 1
24   Element was: 2
25   Element was: 3
26   Element was: 4
27   Element was: 5
dis()

这次让我们简单点,只看看 Python 如何执行for-loop

1   from dis import dis
2
3   dis('''
4   for number in the_count:
5       print(number)
6   ''')

这次我将在这里重现输出,以便我们可以分析它:

 1    0 LOAD_NAME     0 (the_count) # get the count list2    2 GET_ITER                    # start iteration3    4 FOR_ITER      6 (to 18)     # for-loop jump to 184    6 STORE_NAME    1 (number)    # create number variable56    8 LOAD_NAME     2 (print)     # load print()7   10 LOAD_NAME     1 (number)    # load number8   12 CALL_FUNCTION 1             # call print()9   14 POP_TOP                     # clean stack
10   16 JUMP_ABSOLUTE 2 (to 4)      # jump back to FOR_ITER at 4
11
12   18 LOAD_CONST    0 (None)      # jump here when FOR_ITER done
13   20 RETURN_VALUE

FOR_ITER操作中我们看到了一个新的东西。这个操作通过以下步骤使for-loop工作:

  1. 调用the_count.__next__()

  2. 如果the_count中没有更多元素,则跳转到 18

  3. 如果仍然有元素,则继续执行

  4. STORE_NAME然后将the_count.__next__()的结果赋给名为number的变量

这就是for-loop实际上所做的一切。它主要是一个单字节代码FOR_ITER,结合其他几个来遍历列表。

学习练习

  1. 看看你如何使用了range。查阅range函数以了解它。

  2. 在第 22 行完全避免了那个for-loop,直接将range(0,6)赋给elements,你能做到吗?

  3. 查找关于列表的 Python 文档并阅读它们。除了append之外,你还可以对列表进行哪些操作?

常见学生问题

如何创建二维(2D)列表? 就像这样的列表中嵌套列表:[[1,2,3],[4,5,6]]

列表和数组不是一回事吗? 这取决于语言和实现。在传统术语中,列表与数组非常不同,因为它们的实现方式不同。在 Ruby 中,它们称之为“数组”。在 Python 中,它们称之为“列表”。现在只需称之为“列表”,因为这是 Python 的称呼。

为什么 for 循环能够使用尚未定义的变量? 变量在循环开始时由 for 循环 定义,每次迭代时将其初始化为当前循环元素。

为什么 for i in range(1, 3): 只循环两次而不是三次? range() 函数只生成从第一个到最后一个的数字,不包括最后一个。因此,在上述情况下它在两处停止,而不是三处。这实际上是这种循环最常见的方式。

elements.append() 做什么?它简单地将元素附加到列表的末尾。打开 Python shell 并尝试用自己创建的列表做几个示例。每当遇到这样的情况时,总是尝试在 Python shell 中进行交互操作。

练习 34:While 循环

现在让我们用一个新的循环完全震惊你,while-loopwhile-loop会持续执行其下的代码块,只要布尔表达式为True

等等,你一直跟上术语了吗?如果我们写一行并以:(冒号)结尾,那告诉 Python 开始一个新的代码块?然后我们缩进,这就是新代码。这一切都是关于构建你的程序,让 Python 知道你的意图。如果你没有理解这个概念,那就回去多做一些关于if语句、函数和for循环的工作,直到你理解为止。

后面我们会有一些练习,训练你的大脑阅读这些结构,类似于我们如何将布尔表达式烙印在你的大脑中。

回到while-loop。它们的作用就像一个if语句的测试,但不同于只运行代码块一次,它们会跳回到while所在的“顶部”,并重复。while循环会一直运行,直到表达式为False

while循环的问题在于:有时它们不会停止。如果你的意图只是一直循环直到宇宙的尽头,那么这很好。否则,你几乎总是希望你的循环最终会结束。

为了避免这些问题,有一些规则需要遵循:

  1. 确保你谨慎使用while循环。通常for循环更好。

  2. 检查你的while语句,并确保布尔测试最终会变为False

  3. 如果有疑问,在while循环的顶部和底部打印出你的测试变量,看看它在做什么。

在这个练习中,你将学习while循环,并在进行以下三个检查时使用它们:

列表 34.1: ex34.py

 1   i = 02   numbers = []34   while i < 6:5       print(f"At the top i is {i}")6       numbers.append(i)78       i = i + 19       print("Numbers now: ", numbers)
10       print(f"At the bottom i is {i}")
11
12
13   print("The numbers: ")
14
15   for num in numbers:
16       print(num)

你应该看到的结果

 1   At the top i is 02   Numbers now: [0]3   At the bottom i is 14   At the top i is 15   Numbers now: [0, 1]6   At the bottom i is 27   At the top i is 28   Numbers now: [0, 1, 2]9   At the bottom i is 3
10   At the top i is 3
11   Numbers now: [0, 1, 2, 3]
12   At the bottom i is 4
13   At the top i is 4
14   Numbers now: [0, 1, 2, 3, 4]
15   At the bottom i is 5
16   At the top i is 5
17   Numbers now: [0, 1, 2, 3, 4, 5]
18   At the bottom i is 6
19   The numbers:
20   0
21   1
22   2
23   3
24   4
25   5
dis()

在我们代码之游戏的最终“支线任务”中,你将使用dis()来分析while-loop的工作原理:

1   from dis import dis
2
3   dis('''
4   i = 0
5   while i < 6:
6       i = i + 1
7   ''')

你已经看到了大部分这些字节码,所以现在轮到你去弄清楚这个dis()输出与 Python 有什么关系了。记住你可以在文档的末尾的[dis()](https://docs.python.org/3/library/dis.xhtml#python-bytecode-instructions)文档中查找所有的字节码。祝你好运!

学习练习

  1. 将这个while-loop转换为一个可以调用的函数,并用一个变量替换测试中的6i < 6)。

  2. 使用这个函数来重写脚本以尝试不同的数字。

  3. 在函数参数中添加另一个变量,你可以传入它,以便你可以更改第 8 行的+ 1,这样你就可以改变增量是多少。

  4. 再次重写脚本以使用这个函数,看看会有什么影响。

  5. 重写它以使用for-loopsrange。你还需要在中间保留增量器吗?如果不去掉它会发生什么?

如果在任何时候你这样做时出现问题(很可能会),只需按住CTRL并按下cCTRL-c),程序就会中止。

常见学生问题

for-循环和**while-循环有什么区别?for-循环只能在“集合”上进行迭代(循环)。while-循环可以进行任何类型的迭代(循环)。然而,while-循环更难正确使用,通常可以用for**-循环完成许多任务。

循环很难。我该如何理解它们? 人们不理解循环的主要原因是因为他们无法跟随代码的“跳跃”。当循环运行时,它会执行其代码块,最后跳回顶部。为了可视化这一点,在循环中到处放置print语句,打印出 Python 在循环中运行的位置以及这些点上变量的设置。在循环之前、顶部、中间和底部编写print行。研究输出并尝试理解正在进行的跳跃。

练习 35:分支和函数

你已经学会了if 语句、函数和列表。现在是时候挑战你的思维了。把这个输入进去,看看你能否弄清楚它在做什么:

列表 35.1: ex35.py

 1   from sys import exit23   def gold_room():4       print("This room is full of gold. How much do you take?")56       choice = input("> ")7       if "0" in choice or "1" in choice:8           how_much = int(choice)9       else:
10           dead("Man, learn to type a number.")
11
12       if how_much < 50:
13           print("Nice, you're not greedy, you win!")
14           exit(0)
15       else:
16           dead("You greedy bastard!")
17
18
19   def bear_room():
20       print("There is a bear here.")
21       print("The bear has a bunch of honey.")
22       print("The fat bear is in front of another door.")
23       print("How are you going to move the bear?")
24       bear_moved = False
25
26       while True:
27           choice = input("> ")
28
29           if choice == "take honey":
30               dead("The bear looks at you then slaps your face off.")
31           elif choice == "taunt bear" and not bear_moved:
32               print("The bear has moved from the door.")
33               print("You can go through it now.")
34               bear_moved = True
35           elif choice == "taunt bear" and bear_moved:
36               dead("The bear gets pissed off and chews your leg off.")
37           elif choice == "open door" and bear_moved:
38               gold_room()
39           else:
40               print("I got no idea what that means.")
41
42
43   def cthulhu_room():
44       print("Here you see the great evil Cthulhu.")
45       print("He, it, whatever stares at you and you go insane.")
46       print("Do you flee for your life or eat your head?")
47
48       choice = input("> ")
49
50       if "flee" in choice:
51           start()
52       elif "head" in choice:
53           dead("Well that was tasty!")
54       else:
55           cthulhu_room()
56
57
58   def dead(why):
59       print(why, "Good job!")
60       exit(0)
61
62   def start():
63       print("You are in a dark room.")
64       print("There is a door to your right and left.")
65       print("Which one do you take?")
66
67       choice = input("> ")
68
69       if choice == "left":
70           bear_room()
71       elif choice == "right":
72           cthulhu_room()
73       else:
74           dead("You stumble around the room until you starve.")
75
76
77   start()

你应该看到什么

这是我玩游戏的样子:

 1   You are in a dark room.2   There is a door to your right and left.3   Which one do you take?4   > left5    There is a bear here.6   The bear has a bunch of honey.7   The fat bear is in front of another door.8   How are you going to move the bear?9   > taunt bear
10   The bear has moved from the door.
11   You can go through it now.
12   > open door
13   This room is full of gold. How much do you take?
14   > 1000
15   You greedy bastard! Good job!

学习练习

  1. 绘制游戏地图以及你如何在其中流动。

  2. 修复所有错误,包括拼写错误。

  3. 为你不理解的函数写注释。

  4. 添加更多内容到游戏中。你能做些什么来简化和扩展它?

  5. gold_room 有一种奇怪的方式让你输入一个数字。这种方式存在哪些错误?你能比我写的更好吗?看看 int() 的工作原理会有提示。

常见学生问题

救命!这个程序怎么运行的!? 当你在理解一段代码时遇到困难时,只需在每一行上面写一个英文注释,解释该行的作用。保持你的评论简短并与代码相似。然后要么画出代码的工作原理,要么写一段描述它的段落。如果你这样做,你就会理解它。

为什么你写了 while True 这会造成一个无限循环。

exit(0) 的作用是什么? 在许多操作系统上,一个程序可以通过 exit(0) 中止,传入的数字将指示是否有错误。如果你使用 exit(1),那么就会有一个错误,但 exit(0) 将是一个良好的退出。它与正常的布尔逻辑相反(0==False)的原因是你可以使用不同的数字来指示不同的错误结果。你可以使用 exit(100) 来表示不同的错误结果,而不同于 exit(2)exit(1)

为什么 input() 有时写成 input('> ') input 的参数是一个字符串,它应该在获取用户输入之前打印作为提示。

练习 36:设计和调试

现在你已经了解了if语句,我将给你一些关于for循环和while循环的规则,这将帮助你避免麻烦。我还会给你一些关于调试的提示,这样你就可以找出程序中的问题。最后,你将设计一个类似于上一个练习但有些不同的小游戏。

从想法到可运行的代码

有一个简单的过程任何人都可以遵循,将你的想法转化为代码。这不是唯一的过程,但对许多人来说效果很好。在你开发自己的个人过程之前,使用这个过程。

  1. 以你理解的任何形式将你的想法表达出来。你是作家吗?那就写一篇关于你的想法的文章。你是艺术家或设计师吗?那就画出用户界面。你喜欢图表吗?看看序列图,这是编程中最有用的图之一。

  2. 为你的代码创建一个文件。是的,信不信由你,这是一个重要的步骤,大多数人都会遇到困难。如果你想不出一个名字,就随便挑一个吧。

  3. 用简单的英语(或者你最容易理解的语言)写下你的想法的描述作为注释。

  4. 从顶部开始,将第一个注释转换为“伪代码”,这有点像 Python,但你不用在意语法。

  5. 将那个“伪代码”转换为真正的 Python 代码,并不断运行你的文件,直到这段代码实现了你的注释所说的。

  6. 重复这个过程,直到你将所有的注释转换为 Python 代码。

  7. 退一步,审查你的代码,然后删除它。你不必一直这样做,但如果你养成丢弃第一个版本的习惯,你将获得两个好处:

a. 你的第二个版本几乎总是比第一个版本好。

b. 你向自己确认这不仅仅是愚蠢的运气。你确实能编写代码。这有助于应对冒名顶替综合症和增强自信。

让我们用一个简单的问题“创建一个简单的华氏度到摄氏度转换器”来做一个例子。第一步,我会写出我对转换的了解:

C 等于 (F - 32 ) / 1.8。我应该询问用户输入 F,然后打印出 C。

一个非常基本的数学公式是理解问题的简单方法。第二步,我写下描述我的代码应该做什么的注释:

1   # ask the user for the F
2   # convert it to a float()
3   # C = (F - 32) / 1.8
4   # print C to the user

一旦我有了这个,我会用伪代码“填空”。我只会做第一行,这样你就可以完成这个:

1   # ask the user for the F
2   F = input(?)
3
4   # convert it to a float()
5   # C = (F - 32) / 1.8
6   # print C to the user

注意,我故意懒惰,没有正确地编写语法,这就是伪代码的要点。一旦我有了这个,就将其转换为正确的 Python 代码:

1   # ask the user for the F
2   F = input("C? ")
3
4   # convert it to a float()
5   # C = (F - 32) / 1.8
6   # print C to the user

运行它! 你应该不断地运行你的代码。如果你输入了超过几行,只需删除它们,重新开始。这样会容易得多。

现在这些行起作用了,我继续下一个注释并重复这个过程,直到我将所有的注释转换成 Python。当我的脚本最终工作时,我会删除它并使用我所知道的重新编写它。也许这一次我直接写 Python,或者我再次重复这个过程。这样做会让我确认自己实际上是可以做到的。这不仅仅是愚蠢的运气。

这是一个专业的过程吗?

你可能会认为这个过程不实用或不专业。我认为,当你刚开始时,你需要不同于那些编程时间很长的人所需的工具。我可以坐下来想一个点子然后编码,但我已经从事专业编程的时间比你活了的时间还长。然而,在我的脑海中,这基本上是我遵循的过程。我只是在脑海中迅速地做这个过程,而你必须在外部练习直到内化。

当我卡住或者在学习一门新语言时,我会使用这个过程。如果我不懂一门语言但知道我想做什么,那么我通常可以写注释然后慢慢将其转换为代码,这也教会我那种语言。我和你之间唯一的区别是,由于多年的训练,我做得更快。

关于“X/Y”非问题

一些专业人士声称,这个过程会让学生患上一种奇怪的疾病,称为“X/Y 问题”。他们将 X/Y 问题描述为“有人想做 X,但只知道如何做 Y,所以他们请求帮助如何做 Y。” X/Y 问题的问题在于它批评了那些简单学习编程的人,并没有提出解决方案。对于“X/Y 问题的讨厌者”,解决方案似乎是“已经知道答案”,因为如果他们知道如何做 X,他们就不会去烦恼 Y。这种信念的虚伪之处在于所有讨厌这种问题的人都经历过这个阶段,提出过这些完全相同的“X/Y”问题。

另一个问题是,他们在责备的糟糕文档。经典的例子来自 X/Y 问题的原始描述:

 1   <n00b> How can I echo the last three characters in a filename?23   <feline> If they're in a variable: echo ${foo: -3}4   <feline> Why 3 characters? What do you REALLY want?5   <feline> Do you want the extension?67   <n00b> Yes.89   <feline> Then ASK FOR WHAT YOU WANT!
10   <feline> There's no guarantee that every filename will
11   have a three-letter extension,
12   <feline> so blindly grabbing three characters does not
13   solve the problem.
14   <feline> echo ${foo##*.}

首先,这个feline人实际上在一个专门回答问题的 IRC 频道里大声责骂某人提问。“要求你想要的东西!”第二个问题是,他们的解决方案是我——一个有几十年经验的 bash 和 Linux 专业人士——每次都要查找的东西。这是 bash 中最糟糕文档化、最不可用的功能之一。一个初学者如何能预先知道他们应该使用一些复杂的“dollar brace name pound pound asterisk dot brace”操作?如果在线有简单的文档解释如何做这个操作,这个人很可能不会提出这个问题。如果 bash 实际上一个基本功能来执行这个每个人都需要的非常常见的操作,那将更好。

当涉及“X/Y 问题”时,这实际上只是一个借口,用来责骂初学者是初学者。每个声称讨厌这个问题的人要么根本不写代码,要么绝对在学习编程时确实做过这样的事情。这就是学习编程的方式。您遇到问题并通过学习如何实现解决方案来摸索解决方案。因此,如果遇到像<feline>这样的人,只需忽略他们。他们只是借口找个人发火并感觉自己更优越。

此外,您会注意到在上一个对话中,没有一个人要求看代码。如果<n00b>只是展示了他们的代码,那么<feline>就可以推荐更好的方法来解决问题。问题解决了。我是说,假设<feline>实际上能够编写代码,而不只是在 IRC 中等待着攻击毫无戒备的初学者提问。

if 语句规则

  1. 每个if语句必须有一个else

  2. 如果else部分永远不应该运行,因为这没有意义,那么你必须在else中使用一个 die 函数,打印出错误消息并终止程序,就像我们在之前的练习中所做的那样。这将找到许多错误。

  3. 永远不要嵌套超过两层的if语句,并始终尝试将其保持一层。

  4. if语句视为段落,其中每个if-elif-else组合就像一组句子。在其前后放置空行。

  5. 您的布尔测试应该简单。如果它们复杂,将它们的计算移到函数中的变量中,并为变量使用一个好的名称。

如果您遵循这些简单的规则,您将开始写出比大多数程序员更好的代码。回到上一个练习,看看我是否遵循了所有这些规则。如果没有,请纠正我的错误。

警告!

在现实生活中永远不要成为规则的奴隶。在训练过程中,您需要遵循这些规则以增强思维能力,但在现实生活中,有时这些规则只是愚蠢的。如果您认为某个规则很愚蠢,请尝试不使用它。

循环规则

  1. 仅在需要永久循环时才使用while循环,这意味着可能永远不会用到。这仅适用于 Python;其他语言不同。

  2. 对于所有其他类型的循环,请使用for循环,特别是在需要循环的事物数量是固定或有限的情况下。

调试提示

  1. 不要使用“调试器”。调试器就像对生病的人进行全身扫描一样。您不会得到任何具体有用的信息,而会发现许多无用且令人困惑的信息。

  2. 调试程序的最佳方法是使用print打印出程序中变量的值,以查看它们出错的位置。

  3. 确保程序的各个部分在编写时能够正常工作。不要在尝试运行之前编写大量的代码文件。少写一点,运行一点,修复一点。

作业

现在编写一个类似于我在上一个练习中创建的游戏。它可以是你想要的任何类型的游戏,但风格相同。花一周的时间让它尽可能有趣。在学习练习中,尽可能使用列表、函数和模块(还记得练习 13 中的那些吗?),并找到尽可能多的新的 Python 片段来使游戏运行。

在开始编码之前,你必须为你的游戏绘制一张地图。在编码之前,先在纸上创建玩家必须经过的房间、怪物和陷阱。

有了地图后,尝试着编写代码。如果在地图中发现问题,那就调整它,使代码与之匹配。

在软件开发中,最好的方法是像这样分成小块:

  1. 在一张纸上或一张索引卡上,写下你需要完成的任务列表,以完成软件开发。这就是你的待办事项清单。

  2. 从你的清单中选择最容易的任务。

  3. 在你的源文件中写下英文注释,作为你在代码中如何完成这个任务的指南。

  4. 在英文注释下面写一些代码。

  5. 快速运行你的脚本,看看代码是否有效。

  6. 保持在写一些代码、运行测试并修复直到它有效的循环中工作。

  7. 将这个任务从你的清单上划掉,然后选择下一个最容易的任务并重复。

这个过程将帮助你以一种系统和一致的方式来开发软件。在工作时,通过删除你实际不需要的任务并添加你需要的任务来更新你的清单。

练习 37:符号复习

现在是时候复习你所知道的符号和 Python 关键字,并尝试在接下来的几节课中学习更多。我已经列出了所有重要的 Python 符号和关键字。

在这节课中,首先尝试从记忆中写出每个关键字的作用。接下来,在网上搜索它们,看看它们真正的作用。这可能很困难,因为有些很难搜索,但无论如何都要尝试。

如果你从记忆中记错了其中一个,就制作一张正确定义的索引卡,尝试“纠正”你的记忆。

最后,在一个小的 Python 程序中使用这些中的每一个,或者尽可能多地完成。目标是找出符号的作用,确保你理解正确,如果不正确就纠正,然后使用它来牢记。

关键字

图片图片

数据类型

对于数据类型,写出每种数据类型的组成部分。例如,对于字符串,写出如何创建一个字符串。对于数字,写出一些数字。

图片

字符串转义序列

对于字符串转义序列,将它们用在字符串中,确保它们执行你认为的操作。

图片

旧式字符串格式

对于字符串格式也是一样:在一些字符串中使用它们,以了解它们的作用。

图片

旧版 Python 2 代码使用这些格式化字符来实现 f-strings 的功能。尝试它们作为替代方案。

运算符

其中一些可能对你来说很陌生,但无论如何都要查找它们。找出它们的作用,如果你仍然无法弄清楚,就留到以后再看。

图片

大约花一周的时间,但如果你更快完成,那就太好了。重点是尝试覆盖所有这些符号,并确保它们牢记在你的脑海中。同样重要的是找出你知道的东西,这样你就可以以后修复它。

阅读代码

现在找一些 Python 代码来阅读。你应该阅读任何你能找到的 Python 代码,并尝试窃取你发现的想法。你实际上应该有足够的知识来阅读,但也许不理解代码的作用。这节课教你如何应用你学到的东西来理解别人的代码。

首先,打印出你想要理解的代码。是的,打印出来,因为你的眼睛和大脑更习惯于阅读纸张而不是电脑屏幕。确保每次打印几页。

其次,浏览你的打印输出,并对以下内容做笔记:

  1. 函数及其作用。

  2. 每个变量首次被赋值的地方。

  3. 程序中不同部分中具有相同名称的任何变量。这些以后可能会有麻烦。

  4. 没有else子句的if语句。它们正确吗?

  5. 任何可能不会结束的while循环。

  6. 任何你因为任何原因无法理解的代码部分。

第三,一旦你标记了所有这些,尝试通过写注释来向自己解释。解释函数,它们如何被使用,涉及哪些变量以及你可以找出这段代码的任何内容。

最后,在所有困难的部分,逐行追踪每个变量的值,逐个函数地。实际上,再做一份打印输出,并在边缘写下你需要“追踪”的每个变量的值。

一旦你对代码的功能有了很好的理解,回到电脑上再次阅读它,看看是否能发现新的东西。继续找到更多的代码并这样做,直到你不再需要打印输出为止。

学习练习

  1. 找出“流程图”是什么,并画几个。

  2. 如果你在阅读代码时发现错误,请尝试修复它们,并将更改发送给作者。

  3. 当你不使用纸张时的另一种技巧是在代码中用#注释来记录你的笔记。有时,这些注释可能成为实际的注释,帮助下一个人。

常见学生问题

我该如何在网上搜索这些内容? 只需在你想要查找的任何内容前加上“python3”。例如,要查找yield,搜索python3 yield

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/715591.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Home-credit海外贷款信贷产品源码/线上贷款产品大全/贷款平台软件源码/海外借贷平台

测试环境&#xff1a;Linux系统CentOS7.6、宝塔、PHP7.3、MySQL5.6&#xff0c;根目录public&#xff0c;伪静态laravel5&#xff0c;开启ssl证书 语言&#xff1a;中文简体、英文 laravel框架的程序有点多&#xff0c;这个团队估计主要就是搞laravel开发的&#xff0c;基本上…

YOLOv9独家原创改进|增加SPD-Conv无卷积步长或池化:用于低分辨率图像和小物体的新 CNN 模块

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、文章摘要 卷积神经网络(CNNs)在计算即使觉任务中如图像分类和目标检测等取得了显著的成功。然而&#xff0c;当图像分辨率较低或物体较小时&…

可以用来测试的接口

实际开发过程中&#xff0c;我们可以通过postman工具来测试接口 get请求 https://api.github.com/events?id1&nameuser post请求 http://httpbin.org/post 参数1&#xff1a;key1value1 参数2&#xff1a;key2value2

(C语言)回调函数

回调函数是什么&#xff1f; 回调函数就是⼀个通过函数指针调⽤的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另⼀个函数&#xff0c;当这个指针被⽤来调⽤其所指向的函数 时&#xff0c;被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅…

技术阅读周刊第十四期:常用的 Git 配置

技术阅读周刊&#xff0c;每周更新。 历史更新 20231122&#xff1a;第十一期20231129&#xff1a;第十二期20240105&#xff1a;第十三期&#xff1a;一些提高生产力的终端命令20240112&#xff1a;第十四期&#xff1a;Golang 作者 Rob Pike 在 GopherConAU 上的分享 How I w…

探索Manticore Search:开源全文搜索引擎的强大功能

在当今信息爆炸的时代&#xff0c;数据的快速检索变得至关重要。无论是在电子商务网站、新闻门户还是企业内部文档&#xff0c;高效的搜索引擎都是确保用户满意度和工作效率的关键因素之一。而在搜索引擎领域&#xff0c;Manticore Search 作为一款开源的全文搜索引擎&#xff…

大模型(LLM)的量化技术Quantization原理学习

在自然语言处理领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;在自然语言处理领域的应用越来越广泛。然而&#xff0c;随着模型规模的增大&#xff0c;计算和存储资源的需求也急剧增加。为了降低计算和存储开销&#xff0c;同时保持模型的性能&#xff0c;LLM大模型…

2024最新算法:鹦鹉优化算法(Parrot optimizer,PO)求解23个基准函数(提供MATLAB代码)

一、鹦鹉优化算法 鹦鹉优化算法&#xff08;Parrot optimizer&#xff0c;PO&#xff09;由Junbo Lian等人于2024年提出的一种高效的元启发式算法&#xff0c;该算法从驯养的鹦鹉中观察到的觅食、停留、交流和对陌生人行为的恐惧中汲取灵感。这些行为被封装在四个不同的公式中…

c语言--qsort函数(详解)

目录 一、定义二、用qsort函数排序整型数据三、用qsort排序结构数据四、qsort函数的模拟实现 一、定义 二、用qsort函数排序整型数据 #include<stdio.h> scanf_S(int *arr,int sz) {for (int i 0; i < sz; i){scanf("%d", &arr[i]);} } int int_cmp(c…

解决在 Mac 上安装 Adobe 软件弹出提示:安装包已经被损坏并且不能被打开。

问题&#xff1a; “INSTALLER” is damaged and can’t be opened. You should eject the disk image. 解决方法和步骤&#xff1a; 打开安装包&#xff1b;将安装包 “INSTALLER” 拖动复制到某个文件夹&#xff0c;复制后的文件路径例如像这样&#xff1a;/Users/michael…

LLC谐振变换器变频移相混合控制MATLAB仿真

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 基本控制原理 为了实现变换器较小的电压增益&#xff0c;同时又有较 高的效率&#xff0c;文中在变频控制的基础上加入移相控制&#xff0c; 在这种控制策略下&#xff0c;变换器通过调节一次侧开关管 的开关…

leetcode 热题 100_盛最多水的容器

题解一&#xff1a; 双指针遍历&#xff1a;容量计算公式为min(左高度&#xff0c;右高度)*底部距离&#xff0c;我们可以令底部距离逐步递减&#xff08;左右两边的指针向中部移动&#xff09;。此时对于min(左高度&#xff0c;右高度)&#xff0c;假设较高的线向中部移动&…

带你玩转数据结构-单链表(适合初学者的文章,讲解的很仔细哦)

前言: &#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f; C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:讲解数据结构中链表的知识,;链表的分类,c语言实现单链…

腾讯云幻兽帕鲁服务器使用Linux和Windows操作系统的具体性能比较是什么?

腾讯云幻兽帕鲁服务器使用Linux和Windows操作系统的具体性能比较是什么&#xff1f; 首先&#xff0c;从内核效率来看&#xff0c;Linux在同等硬件条件下的性能优于Windows。这是因为Linux内核设计简洁&#xff0c;对服务器工作负载进行了优化&#xff0c;能够更好地利用系统资…

Python学习 day07(JSON)

JSON 各种编程语言存储数据的容器不尽相同&#xff0c;在Python中有字典dict这样的数据类型&#xff0c;而其他语言可能没有对应的字典&#xff0c;为了让不同的语言都能够相互通用的传递数据&#xff0c;JSON就是一种非常良好的中转数据格式&#xff0c;如下&#xff1a; JSON…

mTSL: netty单向/双向TLS连接

创建证书 不管是单向tls还是双向tls(mTLS)&#xff0c;都需要创建证书。 创建证书可以使用openssl或者keytool&#xff0c;openssl 参考 mTLS: openssl创建CA证书 单向/双向tls需要使用到的相关文件: 文件单向tls双向tlsServer端Client端备注ca.key----需要保管好&#xff0…

【Web安全靶场】sqli-labs-master 38-53 Stacked-Injections

sqli-labs-master 38-53 Stacked-Injections 其他关卡和靶场看专栏… 文章目录 sqli-labs-master 38-53 Stacked-Injections第三十八关-报错注入第三十九关-报错注入第四十关-盲注第四十一关-盲注第四十二关-联合报错双查询注入第四十三关-报错注入第四十四关-盲注第四十五关-…

「爬虫职海录」三镇爬虫

HI&#xff0c;朋友们好 「爬虫职海录」第三期更新啦&#xff01; 本栏目的内容方向会以爬虫相关的“岗位分析”和“职场访谈”为主&#xff0c;方便大家了解一下当下的市场行情。 本栏目持续更新&#xff0c;暂定收集国内主要城市的爬虫岗位相关招聘信息&#xff0c;有求职…

【高级数据结构】Trie树

原理 介绍 高效地存储和查询字符串的数据结构。所以其重点在于&#xff1a;存储、查询两个操作。 存储操作 示例和图片来自&#xff1a;https://blog.csdn.net/qq_42024195/article/details/88364485 假设有这么几个字符串&#xff1a;b&#xff0c;abc&#xff0c;abd&…

Vue中如何实现条件渲染?

在Vue中实现条件渲染非常简单且灵活&#xff0c;主要通过Vue的指令来实现。在Vue中&#xff0c;我们可以使用v-if和v-else指令来根据条件来渲染不同的内容。下面就让我们通过一个简单的示例来演示如何在Vue中实现条件渲染&#xff1a; <!DOCTYPE html> <html lang&qu…