Files
team-learning-program/PythonThinking/task6-FOR、IF以及while.md
2023-06-28 14:24:57 +08:00

19 KiB
Raw Blame History

4 FOR、IF以及while

4.1 IF语句

4.1.1 IF语句的使用

:linenos:

people = 20
cats = 30
dogs = 15


if people < cats:
    print("Too many cats! The world is doomed!")

if people > cats:
    print("Not many cats! The world is saved!")

if people < dogs:
    print("The world is drooled on!")     

if people > dogs:
    print("The world is dry!")


dogs += 5

if people >= dogs:
    print("People are greater than or equal to dogs.")

if people <= dogs:
    print("People are less than or equal to dogs.")


if people == dogs:
    print("People are dogs.")

  上述代码的运行结果:

Too many cats! The world is doomed!     
The world is dry!
People are greater than or equal to dogs.
People are less than or equal to dogs.
People are dogs.
:class: tip

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

1. 你认为`if`对它下面的代码起什么作用?
2. 为什么`if`下面的代码要缩进 4 个空格?
3. 如果没有缩进会发生什么?
4. 你能把一些布尔表达式放进`if`语句吗?试试看。
5. 如果你改变`people`、`cats`和`dogs`的初始值会发生什么?

常见问题

+=是什么意思?

答: x += 1就相当于x = x + 1但是输入的内容更少。你可以把它叫做“累加”increment by运算符。之后你还会学到-=这样类似的表达。

4.1.2. Else 和 IF 使用

  在上个练习中你学到了一些if语句,思考了它的含义和作用。在你学习更多内容之前,我会解释一下上个附加练习中的问题。首先确定你做了那些练习。

  1. 你认为if对它下面的代码起什么作用?

if语句在代码中创建了一个“分支”branch有点类似于在一本冒险书中你选择了哪个答案就翻到对应的一页如果你选择了不同的答案就会去到不同的地方。if语句就是告诉脚本,如果这个布尔表达式是True,那就运行它下面的代码,否则的话就跳过。

  1. 为什么if下面的代码要缩进 4 个空格?

  通过一行代码结尾的冒号告诉 Python 你在创建一个新的代码块,然后缩进四个空格告诉 Python 这个代码块中都有些什么。这就跟本书前半部分中你学的函数是一样的。

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

如果没有缩进你很可能收到一个错误提示。Python 一般会让你在一个带:的代码行下面缩进一些内容。

  1. 你能把一些布尔表达式放进if语句吗?试试看。

  试试吧,你可以的。你可以把它们写得很复杂,不过复杂的东西一般风格都很糟糕。

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

  因为在比较数字,所以如果改变了数字,不同的if语句将会得出不同的判断结果,那么下面某些代码块就有可能运行。回到练习中给这些变量一些不同的数值,然后看看你能否在脑中判断出来哪些代码块会运行。

  把我的答案和你的比较一下,然后确保你真的理解了代码块的概念。这对你进行接下来的练习很重要。把下面的代码输入进去然后运行。

:linenos:

people = 30
cars = 40
trucks = 15


if cars > people:
    print("We should take the cars.")
elif cars < people:
    print("We should not take the cars.")
else:
    print("We can't decide.")

if trucks > cars:
    print("That's too many trucks.")
elif trucks < cars:
    print("Maybe we could take the trucks.")
else:
    print("We still can't decide.")

if people > trucks:
    print("Alright, let's just take the trucks.")
else:
    print("Fine, let's stay home then.")

  上述代码的运行结果:

We should take the cars.
Maybe we could take the trucks.
Alright, let's just take the trucks.
:class: tip

1. 试着猜猜`elif`和`else`的作用是什么。
2. 改变`cars`、`people`和`trucks`的数值,然后追溯每一个`if`语句,看看什么会被打印出来。
3. 试试一些更复杂的布尔表达式,比如`cars > people`或者`trucks < cars`。
4. 在每一行上面加上注释。

常见问题

如果多个elif块都是True会发生什么?

答: Python 从顶部开始,然后运行第一个是True的代码块,也就是说,它只会运行第一个。

4.1.3 IF嵌套使用

  前面主要学习了调用函数、打印东西,但是这些基本都是直线运行下来的。你的脚本从上面开始运行,然后到底部结束。如果你用了一个函数,你可以随后再运行它,但是仍然不会有分叉需要你做决定的情况。现在你学习了ifelse以及elif,你就可以让脚本来做决定了。

  在上个脚本中,你写出了一个简单的问问题的测试集。在这个练习中,你将问用户一些问题,并基于他们的回答做决定。写下这个脚本,然后多玩几遍,把它弄明白。

:linenos:

print("""You enter a dark room with two doors.
    Do you go through door #1 or door #2?""")

door = input("> ")

if door == "1":
    print("There's a giant bear here eating a cheese cake.")
    print("What do you do?")
    print("1. Take the cake.")
    print("2. Scream at the bear.")     

    bear = input("> ")

    if bear == "1":
        print("The bear eats your face off. Good job!")
    elif bear == "2":
        print("The bear eats your legs off. Good job!")
    else:
        print(f"Well, doing {bear} is probably better.")
        print("Bear runs away.")

elif door == "2":
    print("You stare into the endless abyss at Cthulhu's retina.")
    print("1. Blueberries.")
    print("2. Yellow jacket clothespins.")
    print("3. Understanding revolvers yelling melodies.")

    insanity = input("> ")

    if insanity == "1" or insanity == "2":
        print("Your body survives powered by a mind of jello.")
        print("Good job!")
    else:
        print("The insanity rots your eyes into a pool of muck.")
        print("Good job!")

else:
    print("You stumble around and fall on a knife and die. Good job!")

  这里很关键的一点是在if语句里面又放了一个if语句。这在创建“嵌套”nested的时候非常有用每一个分支指向另一个选择。

  确保你理解了在if语句中嵌套if语句的理念。可以通过做附加练习来真正掌握它。

你会看到

  这是我玩这个冒险小游戏的结果,我可能玩得没那么好。

You enter a dark room with two doors.     
Do you go through door #1 or door #2?
>   1
There's a giant bear here eating a cheese cake.
What do you do?
1.  Take the cake.
2.  Scream at the bear.
>   2
The bear eats your legs off. Good job!
:class: tip

给这个游戏加一些新内容,同时改变用户可以做的决定。尽可能地扩展这个游戏,直到它变得很搞笑。写一个完全不同的新游戏。可能你不喜欢我的这个,你可以做一个你自己的。

常见问题

  1. 我能用一系列的if语句来代替elif吗?

答: 在某些情况下可以,但是取决于每个if/else是怎么写的。如果这样的话还意味着 Python 将会检查每一个if-else组合,而不是像if-elif-else组合那样只会检查第一个是false的。你可以多试几次,感受一下区别。

  1. 我如何表示一个数字的区间?

答: 有两种方式:一种是0 < x < 10或者1 <= x < 10这种传统表示方法,另一种是x的区间是(1, 10)

  1. 如果我想在if-elif-else代码块中放更多的选择怎么办?

答: 为每种可能的选择增加更多的elif块。

4.2 FOR语句

:linenos:

the_count = [1, 2, 3, 4, 5]
fruits = ['apples', 'oranges', 'pears', 'apricots']
change = [1, 'pennies', 2, 'dimes', 3, 'quarters']

# this first kind of for-loop goes through a list
for number in the_count:
    print(f"This is count {number}")

# same as above
for fruit in fruits:
    print(f"A fruit of type: {fruit}")

# also we can go through mixed lists too
# notice we have to use {} since we don't know what's in it
for i in change:
    print(f"I got {i}")

# we can also build lists, first start with an empty one
elements = []

# then use the range function to do 0 to 5 counts
for i in range(0, 6):
    print(f"Adding {i} to the list.")
    # append is a function that lists understand
    elements.append(i)

# now we can print them out too
for i in elements:
    print(f"Element was: {i}")

  上述代码的运行结果:

This is count 1
This is count 2
This is count 3
This is count 4
This is count 5
A fruit of type: apples
A fruit of type: oranges
A fruit of type: pears
A fruit of type: apricots
I got 1
I got pennies
I got 2
I got dimes
I got 3
I got quarters
Adding 0 to the list.
Adding 1 to the list.      
Adding 2 to the list.
Adding 3 to the list.    
Adding 4 to the list.
Adding 5 to the list.     
Element was: 0
Element was: 1
Element was: 2
Element was: 3
Element was: 4
Element was: 5
:class: tip

1. 看看你是如何使用`range`的。查阅上面的`range`函数并理解掌握。
2. 你能在第 22 行不使用`for-loop`,而是直接把`range(0, 6)`赋给`elements`吗?
3. 找到 Python 文档关于列表的部分,然后读一读。看看除了`append`,你还能对列表做哪些操作?

常见问题

  1. 如何创建一个二维列表?

答: 可以用这种列表中的列表:[[1,2,3],[4,5,6]]

  1. 列表lists和数组arrays难道不是一个东西吗

答: 这取决于语言以及实现方法。在传统术语中,列表和数组的实现方式不同。在 Ruby 中都叫做arrays,在 python 中都叫做lists。所以我们就把这些叫做列表吧。

  1. 为什么for-loop可以用一个没有被定义的变量?

答: 变量在for-loop开始的时候就被定义了,它被初始化到了每一次loop迭代时的当前元素中。

  1. 为什么range(1, 3)中的i只循环了两次而不是三次?

答: range()函数只处理从第一个到最后一个数,但不包括最后一个数,所以它在 2 就结束了。这是这类循环的通用做法。

  1. element.append()的作用是什么?

答: 它只是把东西追加到列表的末尾。打开 Python shell 然后创建一个新列表。任何时候当你遇到类似的用法,试着多玩几次,去体会它们的作用。

4.3 while语句

  现在我们来看一个新的循环:while-loop。只要一个布尔表达式是Truewhile-loop就会一直执行它下面的代码块。

  等等,你应该能理解这些术语吧?如果我们写一行以:结尾的代码,它就会告诉 Python 开始一个新的代码块。我们用这种方式来结构化你的程序,以便 Python 明白你的意图。如果你还没有掌握这块内容,先回去复习一下,再做一些if语句、函数以及for-loop,直到你掌握为止。

  之后我们会做一些练习来训练你的大脑读取这些结构,就像我们训练你掌握布尔表达式一样。

  回到while-loop,它所做的只是像if语句一样的测试,但是它不是只运行一次代码块,而是在whileTrue的地方回到顶部再重复,直到表达式为False

  但是while-loop有个问题:有时候它们停不下来。如果你的目的是让程序一直运行直到宇宙的终结,那这样的确很棒。但大多数情况下,你肯定是需要循环最终能停下来的。

为了避免这些问题,你得遵守一些规则:

  1. 保守使用while-loop,通常用for-loop更好一些。
  2. 检查一下你的while语句,确保布尔测试最终会在某个点结果为False
  3. 当遇到问题的时候,把你的while-loop开头和结尾的测试变量打印出来,看看它们在做什么。

  在这个练习中,你要通过以下三个检查来学习while-loop

:linenos:

i = 0
numbers = []

while i < 6:
    print(f"At the top i is {i}")
    numbers.append(i)

    i = i + 1
    print("Numbers now: ", numbers)
    print(f"At the bottom i is {i}")


print("The numbers: ")

for num in numbers:
    print(num)

  上述代码的运行结果:

At the top i is 0      
Numbers now: [0]
At the bottom i is 1
At the top i is 1    
Numbers now:    [0, 1]
At the bottom i is 2
At the top i is 2
Numbers now:    [0, 1, 2]
At the bottom i is 3
At the top i is 3
Numbers now:    [0, 1, 2, 3]
At the bottom i is 4
At the top i is 4
Numbers now:    [0, 1, 2, 3, 4]
At the bottom i is 5
At the top i is 5
Numbers now:    [0, 1, 2, 3, 4, 5]
At the bottom i is 6
The numbers:
0
1
2
3
4
5
:class: tip

1. 把这个`while-loop`转换成一个你可以调用的函数,然后用一个变量替代`i < 6`里面的`6`。
2. 用这个函数重新写一下这个脚本,试试不同的数值。
3. 再增加一个变量给这个函数的参数,然后改变第 8 行的`+1`,让它增加的值与之前不同。
4. 用这个函数重新写这个脚本,看看会产生什么样的效果。
5. 用`for-loop`和`range`写这个脚本。你还需要中间的增加值吗?如果不去掉这个增加值会发生什么?

注:任何时候你在运行程序的时候它失控了,只用按下 CTRL-C ,程序就会终止。

常见问题

  1. for-loopwhile-loop的区别是什么?

答: for-loop只能迭代(循环)一些东西的集合,而while-loop能够迭代(循环)任何类型的东西。不过,while-loop很难用对,而你通常能够用for-loop完成很多事情。

  1. 循环好难,我应该如何理解它们?

答: 人们不理解循环的主要原因是他们跟不上代码的运行。当一个循环运行的时候,它会过一遍代码块,到结尾之后再跳到顶部。为了直观表现这个过程,你可以用print打印出循环的整个过程,把print行写在循环的前面、顶部、中间、结尾。研究一下输出的内容,试着理解它是如何运行的。

4.4 分支和函数

  目前为止你已经了解了if语句,函数以及列表。现在是时候深入学习一下了。照例输入如下代码,看看你能否明白程序在做什么。

:linenos:

from sys import exit

def gold_room():
    print("This room is full of gold. How much do you take?")

    choice = input("> ")
    if "0" in choice or "1" in choice:
        how_much = int(choice)
    else:
        dead("Man, learn to type a number.")

    if how_much < 50:
        print("Nice, you're not greedy, you win!")
        exit(0)
    else:
        dead("You greedy bastard!")


def bear_room():
    print("There is a bear here.")
    print("The bear has a bunch of honey.")
    print("The fat bear is in front of another door.")
    print("How are you going to move the bear?")
    bear_moved = False

    while True:
        choice = input("> ")

        if choice == "take honey":
            dead("The bear looks at you then slaps your face")
        elif choice == "taunt bear" and not bear_moved:
            print("The bear has moved from the door.")
            print("You can go through it now.")
            bear_moved = True
        elif choice == "taunt bear" and bear_moved:
            dead("The bear gets pissed off and chews your leg.")
        elif choice == "open door" and bear_moved:
            gold_room()
        else:
            print("I got no idea what that means.")


def cthulhu_room():
    print("Here you see the great evil Cthulhu.")
    print("He, it, whatever stares at you and you go insane.")
    print("Do you flee for your life or eat your head?")

    choice = input("> ")

    if "flee" in choice:
        start()
    elif "head" in choice:
        dead("Well that was tasty!")
    else:
        cthulhu_room()


def dead(why):
    print(why, "Good job!")
    exit(0)

def start():
    print("You are in a dark room.")
    print("There is a door to your right and left.")
    print("Which one do you take?")

    choice = input("> ")

    if choice == "left":
        bear_room()
    elif choice == "right":
        cthulhu_room()
    else:
        dead("You stumble around the room until you starve.")


start()

  上述代码的运行结果:

You are in a dark room.
There is a door to your right and left. Which one do you take?
>   left
There is a bear here.
The bear has a bunch of honey.
The fat bear is in front of another door. How are you going to move the bear?
>   taunt bear
The bear has moved from the door. You can go through it now.
>   open door
This room is full of gold.  How much do you take?
>   1000
You greedy bastard! Good job!
:class: tip

1. 画一个这个游戏的流程图,并指出它是如何运转的。
2. 修正你的错误,包括拼写和语法错误。
3. 为你不理解的函数写上注释。
4. 为游戏增加一些功能,同时使代码更加简化。
5. 这个`gold_room`让你输入数字的方式有点奇怪。这样做有哪些`bug`?你能改善我的代码吗?可以查查看`int()`的相关知识。

常见问题

  1. 救命! 这个程序是怎么工作的!?

答: 当你遇到不理解的代码时,不要着急,只要在每行代码下面写下注释,弄清楚这一行是做什么的,就很容易明白。确保你的注释和代码一样简洁。 然后要么画图,要么写一段话来描述代码是如何运行的。这样你就会理解其背后的原理。

  1. 为什么你要用while True

答: 这样可以构建一个无限循环。

  1. exit(0)是干什么用的?

答: 在很多操作系统中,一个程序可以用exit(0)来结束,其中传入的数字代表是否有错误。如果你用exit(1)代表有1个错误exit(0)则代表程序正常退出。它不同于通常的布尔逻辑(0==False),因为你可以用不同的数字来表示不同的错误结果。你可以用exit(100)来表示与exit(2)或者exit(1)不同的错误结果。

  1. 为什么input()有时会被写成input('> ')

答: input的参数是一个字符串,所以要在获取用户输入的内容前面加一个提示符。这里>也可以换成想要提示用户的文字。