02 Accumulation

Terminology

Comments

下面是一個程式的示意圖

def drawLSystem(self, snap):
    '''
    makes the turtle draw out the result created by the createLSystem function
    '''
    #complete this method
    state = []
    for c in self.result:
        if c == 'F':
            snap.forward(self.distance)
        elif c == '+':
            snap.right(self.angle)
        elif c == '-':
            snap.left(self.angle)
        elif c == '[':
            save = {a : d for a,d in snap.__dict__.items()}
            state.append(save)
        elif c == ']':
            if state:
                load_state = state.pop()
                snap.__dict__ = load_state

Python認得空白鍵,而且用縮排來區分程式區塊,一般會用四個空白或一個 tab


程式裡還是會有要給人類看的部分,我們稱作 commentdoc string
如果一次要很多排,就會在前後加上 '''
如果只有單行,就會用 #
這些附註可以讓未來看自己寫的東西時,不會完全不懂


bool

在 Python 五花八門的內建 type 裡,有一種是幾乎所有程式語言都有的,那就是 boolean

bolean 簡稱 bool 中文是布林,簡單來說,就是 TrueFalse
電腦的世界只有 0 和 1,在這裡 0 是 False, 1 是 True


bool 是一種 type,這種 type 就只有 TrueFalse
或代表 True 或 False 的變數

布林的判斷是用兩個等於 ==
不等於是 !=
大於等於 >=
小於等於 <=

試試

print(3 == 4)
print(3 != 4)
print(3 = 4)

True 就是會發生的事,False 就是不會發生的事

在Python裡,所有亂七八糟的東西都是 True, 只有 0, False, [], "", None 是 False


Boolean operators

試試下面

print(True and True)
print(True and False)
print(True or False)
推敲出 andor 的用法了嗎?

and 要兩者都有才能成立
or 只要一個成立就成立


想想看下面會是什麼呢?

print(not(True and False))
print(True or False or False)

還有許多其他的 Boolean operators 這邊就先不詳細介紹

依然不懂的話

快速,但原理不全然正確的理解方式還有:and 是乘法,or 是加法
所以既然 True 是 1,False 是 0,兩個變數用加法跟乘法得到的值就是最後的 boolean 值

別人的圖解如下




Member Functions or Methods

之前介紹過各式各樣內建的 type,像是 int ,str, float, 也有說還有一種東西叫 class,之前的解釋是「 一個 object,可以理解成自己寫的一種 type」,其實這些內建的 type 也可以理解成一種 class

Everything in Python is an object.
這就是物件導向 Object-oriented programming

糾結這些的意義在於知道他們的共通點與用法,而 class或說 objects 們的其中一種特性就是他們有自己旗下的 function,這些專屬於這種 type 的 function 叫作 member functionsmethods
(Python 裡叫 methods,但很多其他語言都叫 member functions

呼叫,或者說 call a function on an object 的方法是靠 .
試試

f = 3.14
my_str = "hello"

print(f.is_integer())
print(my_str.islower())
print(my_str.isnumeric())
print(my_str.upper())

之前說 function 會有 return 的值,也就是函數 y = f(x) = ax + b 裡的 y

像是 is_integer() 回傳的值就是那一個 (限 float 的) object 能不能無痛變成 int,所以 return type 是 boolean
upper() 回傳的就是那一個 (限 str 的) object 變成全部大寫的版本,所以 return type 是 string

關於 functions 或 methods 之後會再出現,目前先介紹怎麼使用內建的而已


至於 methods 當然還有很多很多可以用的,例如一個 string 就佔了這多:
Python documentation string methods

所以寫程式時通常只會記得常見的,其他就 google 囉


Iteration

現在來介紹一些程式的重要元素
首先,先理解下面這段程式的意思

a = 0
print(a)
a = a + 1
print(a)
a = a + 1
print(a)
a = a + 1
print(a)
a = a + 1
print(a)
a = a + 1
print(a)

會印出什麼呢?

簡單來說,有一個變數 a,被加了五次 1
但這樣寫非常沒有意義,而且也很佔空間,於是在很多語言裡就出現 累加器 Accumulator
這邊介紹 forwhile


這兩個東西都叫 迴圈 loop ,意思是不斷輪迴的東西
要介紹迴圈之前,我們先看兩個常常和和迴圈搭配的東西 range


range

range 就是範圍,是一種 class
用法如下

range(0, 10, 2)    #range(開頭, 結尾, 間隔)

如果把上面 range 裡面的數字都印出來,會是0, 2, 4, 6, 8

range 會涵蓋開頭,但不包含結尾
當然,也有不用填滿三格的用法:

range(0, 10)        #這個的間隔是 1
range(10)           #開頭的預設是 0

想想看下面這些各含哪些數字

range(10, 0)
range(3, 11, 4)



Conditional Statements

現在我們來看假設句 if, else, elif
elif 就是 else if 的意思


試著解讀下面程式

a = True
b = True

if (a):
    print("a is True!")
elif(b):
    print("b is True")
else:
    print("no one is True")

最後會印出什麼呢?
a is True!



這就是假設的用法


for Loops

拉回正題,我們來看迴圈
仔細比較,下面這兩個是一樣的東西

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




for 就是一個這樣的累加器
會一行一行的跑,直到「離開了這個迴圈」再繼續往下一行邁進


下面是一個計算正方形面積的程式

length = int(input("enter the length: "))    #輸入邊長

answer = 0                                   #一開始的面積計算是0

for i in range(length):
    answer = answer + length                 #每一次都在原本的數值上加上邊長

print(answer)                                #印出答案

如果想要看它每一次加的過程,可以把 print 移到迴圈裡,
這樣每跑一次迴圈,就會印出當下的結果唷



現在寫一個能要求使用者輸入兩個邊長,然後用累加器計算相乘結果的程式吧!


while Loops

如果說 for loop 就是跑完範圍就會結束跳往下一行,
那麼 while loop 就是永遠不會主動結束的迴圈
常常,我們都會卡在結束不了的迴圈裡,有時候還要強制關機呢(笑)


以上面的程式為例,如果我們把 for loop 換成 while loop 就會變下面這樣:

length = int(input("enter the length: "))    #輸入邊長

answer = 0                                   #一開始的面積計算是0

while(True):
    answer = answer + length                 #每一次都在原本的數值上加上邊長

print(answer)                                #印出答案(永遠不會發生QQ)

這時候,answer 就會一直加一直加,永不停止
程式一直卡在 while loop 裡面沒有辦法跳出來,到下面的 print(answer) 那邊


我們把 print 放到迴圈裡面看看吧,這時候就可以真真實實感受到 infinite loop 的恐怖囉


上面無限迴圈很明顯地,問題就出在

while(True)

這邊,括號內的是這個 loop 進行的條件,如果是 True 就會跑一次這個迴圈
上面放了 True,而 True == True,所以當然是一直跑囉


所以我們來改變看看條件
最簡單的方式就是再加入一個計算迴圈跑幾次的 counter
試試

length = int(input("enter the length: "))    #輸入邊長

answer = 0                                   #一開始的面積計算是0

counter = 0                                  #計算迴圈次數

while(counter < length):
    answer = answer + length                 #每一次都在原本的數值上加上邊長
    counter = counter + 1

print(answer)                                #印出答案

依照上面的程式,如果輸入 10,會印出什麼呢?


100


現在把之前寫過的,拿來計算長方形公式的 for loop 改成 while


break

其實要離開或說結束一個迴圈還有很多方法
例如我們可以在迴圈裡用 if 來控制
關鍵字 break 就是結束迴圈的意思
試試

run = 0
while(True):
    run = run + 1
    if (run > 10):
            break
    else:
            print("loop still running!")

print("loop ended!")



Modules

迴圈是程式裡不可或缺的部分,它可以在讓程式簡短很多的同時完成許多其他事
後面會再介紹更多用法
現在我們的程式架構愈來愈複雜完整了,這裡再介紹一個好用的東西:
Module 模組
白話文是:別的地方來的 code,不論是 type 或 function



Python 有很多好用的 module 很多都是內建的,只要跟著指示就可以了
想要使用時,在程式開頭用 import 引進
以下介紹兩個

import random

顧名思義,random 就是隨機的意思
引進來的 random 是一個 object(或 class 或 type :)
可以幫你產出各種隨機的東西
我們來用用 random.randrange()用法點我

根據既有的知識,既然 random 是一個 object、randrange() 後面有括號、兩者之間還是一個點,那麼 randrange 就是 random 旗下的 method 了




簡單來說,如果要在 range(10) 中選一個整數,就用 random.randrange(10)

翻成中文就是
「手上有一個被 import 進來的 random object 了」
「現在要對我的 random object 使用 randrange」
「使用 randrange 時帶入 10,這樣它就知道我的範圍了」




現在寫一個抽籤的程式吧

參考架構如下

  • 一個變數(user input)代表「使用者輸入班上人數」
  • 一個變數(user input)代表「使用者輸入要抽出的人數」
  • 用一個 for loop 一次抽一個人,然後印出來
  • 最後說抽籤結束

寫出來之後想想看

  1. 要怎麼讓最後一號也有被抽到的機會?
  2. 萬一使用者輸入的「要抽出的人數」比「全班人數」多,怎麼辦?
  3. 有辦法把 for loop 換成 while loop 嗎?



現在來介紹另一個

import time

用法點我

常用的有 time.sleep()
可以讓程式跑得不那麼快


至於取得當下時間,我偏好使用另一個 moduledatetime

不過這個比較特別,在 import 的時候,我們會用

from datetime import datetime

因為 datetime 本身是一個更大的 object,我們只有要用到它旗下的 datetime object 而已(可以理解成,對,它跟它旗下的 object 撞名
要叫出當下時間,可以用 datetime.now()datetime.today()


如果上面一開始不是寫 from datetime import datetime
而是只有 import datetime
這邊要叫出時間就要變成

datetime.datetime.now() 或 datetime.datetime.today()




各種 module 的用法我們後面會再解釋
簡單來說,第一個 datetime 是一個裝了很多模組的大資料夾,第二個則是我們要的模組
now()today() 是模組裡的功能
我們透過 點. 來一層一層進入



References

function vs. method https://www.geeksforgeeks.org/difference-method-function-python/

Additional Readings

chapter8.2 https://runestone.academy/ns/books/published/thinkcspy/MoreAboutIteration/Theforlooprevisited.html
chapter8.3 https://runestone.academy/ns/books/published/thinkcspy/MoreAboutIteration/ThewhileStatement.html
chapter5 https://runestone.academy/ns/books/published/thinkcspy/PythonModules/toctree.html