Python繪圖專題 === 在七年級的Scratch單元中,我們曾經使用畫筆積木來繪製有規律的圖案,同樣地,這些圖案也可以用Python的Turtle繪圖模組來實作。這個模組之所以命名為Turtle,概念是源自於 Seymour Papert 和 Wally Feurzig 於1966 年所創造用來引導孩子們學習程式設計的海龜繪圖(Logo)程式語言。 一個Python模組是一個檔案,內含Python程式指令,可以提供其他Python程式應用。只要匯入模組,就可以使用在模組裡事先定義的函式或變數。例如:匯入 turtle 模組後,就可以使用 Screen()方法來產生畫布,或是使用 Turtle() 方法產生一個海龜進行繪圖,這二個方法都是在 turtle 模組裡定義的。 ### Turtle繪圖座標 ![](https://i.imgur.com/iL76vdw.png) :::warning :bulb:小提示 import 匯入 forward 往前 right 右邊 screen 螢幕 turtle 海龜 exit 離開 click 點擊 range 範圍 ::: 透過import turtle(匯入turtle繪圖模組)這行敘述的執行,Python就會多知道了許多關於海龜繪圖的指令。首先,執行 window = turtle.Screen()及 john = turtle.Turtle()這二行指令,你可以想像在 x-y 平面上,有一隻叫做 john 的海龜(Python預設圖案是箭頭)位於原點(0,0)的位置。 Python是一個物件導向的程式語言,利用「點」符號可以使用模組裡的資料,例如使用 turtle 模組裡的 Turtle()方法可以寫成 turtle.Turtle(),以中文來解讀意思是:「在 turtle 模組中,取用名為 Turtle 的方法」。這個方法會傳回一個海龜物件,我們將這個物件指定給 john 這個變數來儲存,你也可以為你的海龜取一個英文名字。 在執行了 window=turtle.Screen()這行指令之後, window 這個變數就會儲存一個畫布物件,並且繼承 turtle 模組事先定義的畫布物件的屬性與方法。在使用物件的屬性或方法時,會是使用`.`語法,可以解讀為中文字`的`,而屬性與方法的差別,在於呼叫方法時會帶有`()`(小括號),有時候小括號中會帶有參數傳入給方法進行運算。例如:呼叫設定畫布大小的方法,可以寫成window.setup(480,360),解讀為中文即是畫布的大小設定為寬480像素,高360像素。呼叫設定畫布顏色的方法,可以寫成window.bgcolor("lightgreen"),解讀為中文即 是畫布的背景色設為淺綠色。在設定畫布背景顏色時,顏色名稱前後要加上單引號或是雙引號,代表它是一個字串,如果沒有加引號,Python會把它當做是變數名稱。 接著,再執行 john.forward(100),這隻叫做 john 的海龜將朝它所面對的方向(預設是x軸正方向)前進100個像素,並且隨著它的移動會畫出一條線段。執行 john.right(90) 指令,這隻海龜就會在原地右轉90度。配合 forward 和 right 這二個指令,我們就可以來用Python練習一下畫方形。 ## 畫方形 ```python= import turtle # 匯入turtle套件,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 window.exitonclick() # 等待使用者關閉視窗 ``` :::warning :bulb:小提示 檔案命名不可以是 turtle.py, 否則會和內建的 turtle 模組名稱互相衝突。 ::: :::warning :bulb:小提示 `#`號後面的文字代表程式註解,Python會忽略它不去執行,程式註解通常是使用自然語言來描述。 ::: 還記得我們在Scratch中(七年級上冊第70頁)怎麼用計次式迴圈來簡化畫方形的程式碼嗎?同樣的,我們在Python中也可以使用計次式迴圈來簡化程式。 ![](https://i.imgur.com/eofhstK.png) 在Scratch中,移動與右轉積木是被嵌入在重複積木中,在Python中,如何表達移動與右轉指令是被嵌入在for迴圈中呢?它是靠文字的縮排來表達。你可以使用空白字元或是tab字元來縮排程式碼,這樣Python就會知道哪裡指令是被包含在迴圈中執行的。要注意的是,縮排時選擇使用空白字元或tab字元時,要使用一致的方法,兩者不能混用,若是混用,雖然眼睛無法分辨其差別,但是Python還是能夠認得他們是不同的字元。 ### for迴圈 ```python= for i in [0,1,2,3]: # 計次式迴圈,重複執行4次 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 ``` `for`和`in`是Python的關鍵字,兩者之間可以放置使用者自訂的變數,而`in`後面接著一個序列,在這個例子中,我們使用了串列 (list),它是序列的其中一種。for迴圈會依序從序列中取得元素,並且將元素指定給前面自訂的迴圈變數(此例為`i`),再執行迴圈裡的內容,直到序列每一元素都被取出過為止。 在Python中,串列(List)是有序的物件集合,具有索引特性,功能類似我們在八年級中學到的陣列(在Scratch中稱為清單)。串列的長度可以變動。要建立串列,可以使用`[]`(中括號),串列中每個元素,使用`,`(逗號) 來區隔。 在上面的例子中,迴圈變數`i`是用來控制迴圈執行的次數,我們並沒有在迴圈中使用到這個變數`i`。另外,我們創造了包含0,1,2,3等4個數字的串列,你也可以使用range()這個Python內建函式來產生這個有規則的整數串列,例如輸入range(4)便會產生一個從0開始,小於4的整數串列,它會回傳[0, 1, 2, 3]這個串列,所以上面的程式碼可以寫成: ```python= for i in range(4): # 計次式迴圈,重複執行4次 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 ``` 所以上面使用循序結構的畫方形的14行程式碼可以改寫成以下使用重複結構的9行程式碼: ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john for i in range(4): # 重複執行4次 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 window.exitonclick() # 等待使用者關閉視窗 ``` ## 擴散方形 ![](https://i.imgur.com/7vw0Y68.png) ![](https://i.imgur.com/03sbsMN.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john for i in range(1,21): # 重複執行20次 john.forward(i*10) # 告訴海龜往前走10+i*10個單位 john.right(90) # 告訴海龜右轉90度 window.exitonclick() # 等待使用者關閉視窗 ``` :::warning :bulb:小提示 range(1,5)會產生一個從1開始,小於5的整數串列,它會回傳[1, 2, 3, 4]這個串列,所以要產生從1開始,到20結束的串列要寫成 range(1, 21)。 ::: ## 旋轉方形 ![](https://i.imgur.com/7dAUrVh.png) ![](https://i.imgur.com/T0D8oQS.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john for i in range(12): # 外層迴圈,重複執行12次 for j in range(4): # 內層迴圈,重複執行4次 john.forward(100) # 告訴海龜往前走100個單位 john.right(90) # 告訴海龜右轉90度 john.right(30) # 告訴海龜右轉30度 window.exitonclick() # 等待使用者關閉視窗 ``` ## 平行方形(1) ![](https://i.imgur.com/VL3mTnQ.png) ![](https://i.imgur.com/YGYLM3B.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 window.setup(480, 360) john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.penup() # 提筆 john.goto(-140, -20) # 告訴海龜定位到(-140,-20)的位置 for i in range(6): # 重複執行6次 john.pendown() # 下筆 for j in range(4): # 重複執行4次 john.forward(30) # 告訴海龜往前走30個單位 john.right(90) # 告訴海龜右轉90度 john.penup() # 提筆 john.forward(60) # 告訴海龜往前走60個單位 window.exitonclick() # 等待使用者關閉視窗 ``` :::warning :bulb:小提示 sum 加總 return 返回 definition 定義 print 印出 draw 繪畫 triangle 三角形 square 正方形 star 星星 goto 前往 pen 筆 down 下 up 上 none 沒有 ::: 在八年級我們曾經使用過Scratch的自訂函式積木來進行程式的模組化設計,在Pythoh中也有相對應的概念。透過函式的撰寫,我們可以將主程式拆解成一個一個的小模組,然後分別去完成後,此外,也可以重複使用這些小模組。 在Python中要定義函式(副程式),是使用def來定義,例如,以下是兩數相加的函式定義: ```python= def sum(a, b): # 定義兩數相加的函式 return a+b # 傳回兩數相加的和 print(sum(2,3)) # 顯示 5 print(sum(6,9)) # 顯示 15 ``` 在上例中,sum是函式名稱,a與b為參數(Parameter)名稱,如果要傳回值則使用return,如果函式執行完畢但沒有使用return傳回值,則傳回None。 ![](https://i.imgur.com/fWV4ipr.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 def draw_triangle(t, size): # 定義畫三角形函式 t.pendown() # 下筆 for i in range(3): # 重複執行3次 t.forward(size) # 告訴海龜往前走size個單位 t.right(120) # 告訴海龜右轉120度 t.penup() # 提筆 def draw_square(t, size): # 定義畫正方形函式 t.pendown() # 下筆 for i in range(4): # 重複執行4次 t.forward(size) # 告訴海龜往前走size個單位 t.right(90) # 告訴海龜右轉90度 t.penup() # 提筆 def draw_star(t, size): # 定義畫星星函式 t.pendown() # 下筆 for i in range(5): # 重複執行5次 t.forward(size) # 告訴海龜往前走size個單位 t.right(144) # 告訴海龜右轉144度 t.penup() # 提筆 window = turtle.Screen() # 產生畫布以進行畫圖 window.setup(480, 360) # 設定畫布大小為寬480像素,高360像素 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.penup() # 提筆 john.goto(-150,0) # 告訴海龜定位到(150, 0)的位置 draw_triangle(john, 50) # 畫一個長度50個單位的三角形 john.forward(80) # 告訴海龜往前走80個單位 draw_square(john, 50) # 畫一個長度50個單位的正方形 john.forward(80) # 告訴海龜往前走80個單位 draw_star(john, 50) # 畫一個長度50個單位的星星 john.forward(80) # 告訴海龜往前走80個單位 window.exitonclick() # 等待使用者關閉視窗 ``` ## 平行方形(2) ![](https://i.imgur.com/VL3mTnQ.png) ![](https://i.imgur.com/qoF73ZQ.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 def draw_square(t, size): # 定義畫正方形函式 t.pendown() # 下筆 for i in range(4): # 重複執行4次 t.forward(size) # 告訴海龜往前走size個單位 t.right(90) # 告訴海龜右轉90度 t.penup() # 提筆 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john for i in range(6): # 重複執行6次 draw_square(john, 30) # 畫一個長度30個單位的正方形 john.forward(50) # 告訴海龜往前走50個單位 window.exitonclick() # 等待使用者關閉視窗 ``` ## 放大方形 ![](https://i.imgur.com/wnUGEmW.png) ![](https://i.imgur.com/44lIfz3.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 def draw_square(t, size): # 定義畫正方形函式 t.pendown() # 下筆 for i in range(4): # 重複執行4次 t.forward(size) # 告訴海龜往前走size個單位 t.right(90) # 告訴海龜右轉90度 t.penup() # 提筆 window = turtle.Screen() # 產生畫布以進行畫圖 window.setup(480, 360) # 設定畫布大小為寬480像素,高360像素 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.penup() # 提筆 john.goto(-120,80) # 告訴海龜定位到(-120,80)的位置 draw_square(john, 50) # 畫一個長度50個單位的正方形 draw_square(john, 100) # 畫一個長度100個單位的正方形 draw_square(john, 150) # 畫一個長度150個單位的正方形 draw_square(john, 200) # 畫一個長度200個單位的正方形 window.exitonclick() # 等待使用者關閉視窗 ``` :::warning :bulb:小提示 from 從..地方 random 隨機 integer 整數 speed 速度 ::: ## 隨機畫星星 ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 from random import randint # 匯入亂數模組,允許我們使用取整數亂數指令 def draw_star(t, size): # 定義畫星星函式 t.pendown() # 下筆 for i in range(5): # 重複執行5次 t.forward(size) # 告訴海龜往前走size個單位 t.right(144) # 告訴海龜右轉144度 t.penup() # 提筆 window = turtle.Screen() # 產生畫布以進行畫圖 window.setup(480, 360) # 設定畫布大小為寬480像素,高360像素 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.speed(8) # 設定海龜的速度為8 for i in range(30): # 重複執行30次 john.penup() # 提筆 x = randint(-200, 200) # 設定變數x為-200~200間的整數亂數 y = randint(-160, 160) # 設定變數y為-160~160間的整數亂數 john.goto(x, y) # 告訴海龜定位到(x,y)的位置 draw_star(john, 50) # 畫一個長度50個單位的星星 window.exitonclick() # 等待使用者關閉視窗 ``` ## 類時鐘(習作) ![](https://i.imgur.com/m5CMOTK.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.penup() # 提筆 john.shape("turtle") # 設定海龜外型 for i in range(12): # 重複執行12次 john.forward(100) # 告訴海龜往前走100個單位 john.stamp() # 蓋章 john.backward(100) # 告訴海龜往後走100個單位 john.right(30) # 告訴海龜右轉30度 window.exitonclick() # 等待使用者關閉視窗 ``` ## 正多邊形(習作) ![](https://i.imgur.com/oRT7nM1.png) ```python= import turtle # 匯入turtle模組,允許我們使用turtle指令 window = turtle.Screen() # 產生畫布以進行畫圖 john = turtle.Turtle() # 建立一個海龜turtle,它的名字叫john john.penup() # 提筆 john.goto(-50, 180) # 告訴海龜定位到(-50, 180)的位置 john.speed(8) # 設定海龜的速度為8 john.pendown() # 下筆 for i in range(10): # 重複執行10次 for j in range(i+3): # 重複執行i+3次 john.forward(100) # 告訴海龜往前走100個單位 john.right(360/(i+3)) # 告訴海龜右轉某個角度 window.exitonclick() # 等待使用者關閉視窗 ```