笨辦法學 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.pswp.cn/news/715591.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715591.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715591.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

怎么快速編輯視頻

背景&#xff1a;怎么簡單快速編輯視頻 利用FFmpeg功能&#xff0c;簡單快速編輯視頻&#xff0c;如按9:16提前剪切視頻、替換背景音樂。 下載FFmpeg&#xff1a;https://ffmpeg.org/download.html 將FFmpeg的路徑添加到環境變量中&#xff1a; Windows&#xff1a;在系統的環…

Home-credit海外貸款信貸產品源碼/線上貸款產品大全/貸款平臺軟件源碼/海外借貸平臺

測試環境&#xff1a;Linux系統CentOS7.6、寶塔、PHP7.3、MySQL5.6&#xff0c;根目錄public&#xff0c;偽靜態laravel5&#xff0c;開啟ssl證書 語言&#xff1a;中文簡體、英文 laravel框架的程序有點多&#xff0c;這個團隊估計主要就是搞laravel開發的&#xff0c;基本上…

前端架構: 腳手架通用框架封裝之腳手架注冊和命令注冊開發(教程二)

腳手架注冊和命令注冊 1 &#xff09;腳手架的注冊 接上文&#xff0c;仍舊在 abc-cli 項目中參考&#xff1a;https://blog.csdn.net/Tyro_java/article/details/136381086之前初始化的時候&#xff0c;使用的是 yargs, 現在我們想要使用 commander在cli包中安裝 commander $…

2024 最新版 Compose material3 下拉刷新

2024 最新版 Compose material3 下拉刷新&#xff0c;版本 > 1.2.0 的 compose material3 已經更新了下拉刷新組件的 Api 見 https://developer.android.com/jetpack/androidx/releases/compose-material3?hlzh-cn#1.2.0 使用方法&#xff1a;https://developer.android.…

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…

消息隊列kafka

消息隊列解決的問題 1. 解耦&#xff0c;通過消息隊列實現應用之間解耦&#xff0c;模塊兒之間解耦 2. 跨線程/進程通信&#xff0c;通過消息隊列傳遞數據&#xff0c;實現不同線程/進程間通信 3. 提升系統穩定性&#xff0c;在高并發場景通過消息隊列緩沖&#xff0c;可以實…

哈啰Java 春招 24屆

時長 1h 3. 為什么使用分布式ID&#xff0c;解決了什么問題 4. Leaf算法了解嗎&#xff1f;講一下原理和工作流程以及優缺點 5. 有沒有可能導致id重復&#xff1f;該如何解決&#xff1f; 6. 項目中redis是如何運用的&#xff1f; 7. 項目中分布式鎖是如何實現的&#xff1f; 8…

解決在 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語言實現單鏈…

重學Springboot3-@import注解的作用

重學Springboot3-import注解的作用 1. 引言2. Import 注解的基本用法3. 導入多個配置類4. 使用 Import 導入組件5. 使用 ImportSelector 和 ImportBeanDefinitionRegistrar6. 總結 1. 引言 在 Spring Framework 中&#xff0c;Import 注解是一個重要的元注解&#xff0c;它允許…

Linux 定時備份文件到另一臺服務器

1. 需求 用戶要求將 Tomcat 的日志文件定時備份到另一臺服務器。同事給我提供了一個寫好的 java 框架&#xff0c;但實在不想給用戶再維護另一個服務了&#xff0c;所以另尋他法。 2. 問題 使用 scp 等跨服務器傳輸命令時需要手動輸入用戶名的密碼才可進行文件傳輸&#xff…