# 02 Accumulation
## Terminology
:::success
**Comments**
:::
下面是一個程式的示意圖 <br/> <br/>
```python
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\
<br/>
程式裡還是會有要給人類看的部分,我們稱作 **comment** 或 **doc string**\
如果一次要很多排,就會在前後加上 `'''`\
如果只有單行,就會用 `#`\
這些附註可以讓未來看自己寫的東西時,不會完全不懂 <br/> <br/> <br/>
:::success
**bool**
:::
在 Python 五花八門的內建 type 裡,有一種是幾乎所有程式語言都有的,那就是 boolean
bolean 簡稱 bool 中文是布林,簡單來說,就是 `True` 和 `False`\
電腦的世界只有 0 和 1,在這裡 0 是 `False`, 1 是 `True`<br/><br/>
`bool` 是一種 **type**,這種 **type** 就只有 `True` 和 `False`\
或代表 True 或 False 的變數<br/><br/>
布林的判斷是用兩個等於 **==**\
不等於是 **!=**\
大於等於 **>=**\
小於等於 **<=**<br/><br/>
試試
```python
print(3 == 4)
print(3 != 4)
print(3 = 4)
```
`True` 就是會發生的事,`False` 就是不會發生的事<br/><br/>
在Python裡,所有亂七八糟的東西都是 True, 只有 `0`, `False`, `[]`, `""`, `None` 是 False<br/><br/><br/>
:::success
**Boolean operators**
:::
試試下面
```python
print(True and True)
print(True and False)
print(True or False)
```
:::spoiler 推敲出 `and` 和 `or` 的用法了嗎?
<br/>
`and` 要兩者都有才能成立\
`or` 只要一個成立就成立
:::
<br>
想想看下面會是什麼呢?
```python
print(not(True and False))
print(True or False or False)
```
還有許多其他的 Boolean operators 這邊就先不詳細介紹 <br><br>
:::spoiler 依然不懂的話
快速,但原理不全然正確的理解方式還有:and 是乘法,or 是加法
所以既然 True 是 1,False 是 0,兩個變數用加法跟乘法得到的值就是最後的 boolean 值
別人的圖解如下


:::
---
<br>
:::success
**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 functions** 或 **methods**
(Python 裡叫 methods,但很多其他語言都叫 member functions
呼叫,或者說 call a function on an object 的方法是靠 `.`
試試
``` python
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 之後會再出現,目前先介紹怎麼使用內建的而已
<br>
至於 methods 當然還有很多很多可以用的,例如一個 string 就佔了這多:
[Python documentation string methods](https://docs.python.org/3/library/stdtypes.html#string-methods)
所以寫程式時通常只會記得常見的,其他就 google 囉
---
## Iteration
現在來介紹一些程式的重要元素
首先,先理解下面這段程式的意思 <br/>
```python
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** \
這邊介紹 `for` 和 `while` <br/> <br/>
這兩個東西都叫 迴圈 **loop** ,意思是不斷輪迴的東西\
要介紹迴圈之前,我們先看兩個常常和和迴圈搭配的東西 `range` <br/> <br/> <br/>
:::success
**range**
:::
`range` 就是範圍,是一種 class
用法如下
```python
range(0, 10, 2) #range(開頭, 結尾, 間隔)
```
如果把上面 `range` 裡面的數字都印出來,會是0, 2, 4, 6, 8
`range` 會涵蓋開頭,但不包含結尾\
當然,也有不用填滿三格的用法:
```python
range(0, 10) #這個的間隔是 1
range(10) #開頭的預設是 0
```
<br/>
想想看下面這些各含哪些數字
```python
range(10, 0)
range(3, 11, 4)
```
-----
<br/><br/>
:::success
**Conditional Statements**
:::
現在我們來看假設句 `if`, `else`, `elif`\
`elif` 就是 else if 的意思<br/><br/>
試著解讀下面程式
```python
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!_
<br/><br/>
這就是假設的用法
------
:::success
**for Loops**
:::
拉回正題,我們來看迴圈
仔細比較,下面這兩個是一樣的東西
```python
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)
```
```python
a = 0
print(a)
for i in range(5):
a = a + 1
print(a)
```
<br/><br/>
`for` 就是一個這樣的累加器\
會一行一行的跑,直到「離開了這個迴圈」再繼續往下一行邁進<br/><br/>
下面是一個計算正方形面積的程式
```python
length = int(input("enter the length: ")) #輸入邊長
answer = 0 #一開始的面積計算是0
for i in range(length):
answer = answer + length #每一次都在原本的數值上加上邊長
print(answer) #印出答案
```
如果想要看它每一次加的過程,可以把 print 移到迴圈裡,\
這樣每跑一次迴圈,就會印出當下的結果唷<br/><br/><br/>
現在寫一個能要求使用者輸入兩個邊長,然後用累加器計算相乘結果的程式吧!<br/><br/><br/>
:::success
**while Loops**
:::
如果說 `for` loop 就是跑完範圍就會結束跳往下一行,\
那麼 `while` loop 就是永遠不會主動結束的迴圈\
常常,我們都會卡在結束不了的迴圈裡,有時候還要強制關機呢(笑)<br/><br/>
以上面的程式為例,如果我們把 `for` loop 換成 `while` loop 就會變下面這樣:
```python
length = int(input("enter the length: ")) #輸入邊長
answer = 0 #一開始的面積計算是0
while(True):
answer = answer + length #每一次都在原本的數值上加上邊長
print(answer) #印出答案(永遠不會發生QQ)
```
這時候,answer 就會一直加一直加,永不停止\
程式一直卡在 `while` loop 裡面沒有辦法跳出來,到下面的 `print(answer)` 那邊<br/><br/>
我們把 `print` 放到迴圈裡面看看吧,這時候就可以真真實實感受到 infinite loop 的恐怖囉<br/><br/>
上面無限迴圈很明顯地,問題就出在
```python
while(True)
```
這邊,括號內的是這個 loop 進行的條件,如果是 `True` 就會跑一次這個迴圈\
上面放了 `True`,而 True == True,所以當然是一直跑囉<br/><br/>
所以我們來改變看看條件\
最簡單的方式就是再加入一個計算迴圈跑幾次的 **counter**\
試試
```python
length = int(input("enter the length: ")) #輸入邊長
answer = 0 #一開始的面積計算是0
counter = 0 #計算迴圈次數
while(counter < length):
answer = answer + length #每一次都在原本的數值上加上邊長
counter = counter + 1
print(answer) #印出答案
```
依照上面的程式,如果輸入 10,會印出什麼呢?<br/><br/>
_100_<br/><br/>
現在把之前寫過的,拿來計算長方形公式的 `for` loop 改成 `while` 吧<br/><br/><br/>
:::success
**break**
:::
其實要離開或說結束一個迴圈還有很多方法\
例如我們可以在迴圈裡用 `if` 來控制\
關鍵字 `break` 就是結束迴圈的意思\
試試
```python
run = 0
while(True):
run = run + 1
if (run > 10):
break
else:
print("loop still running!")
print("loop ended!")
```
------
<br/>
::: success
**Modules**
:::
迴圈是程式裡不可或缺的部分,它可以在讓程式簡短很多的同時完成許多其他事\
後面會再介紹更多用法\
現在我們的程式架構愈來愈複雜完整了,這裡再介紹一個好用的東西:\
Module 模組
白話文是:別的地方來的 code,不論是 type 或 function<br/><br/><br/>
Python 有很多好用的 module 很多都是內建的,只要跟著指示就可以了\
想要使用時,在程式開頭用 `import` 引進 \
以下介紹兩個<br/><br/>
```python
import random
```
顧名思義,`random` 就是隨機的意思\
引進來的 random 是一個 object(或 class 或 type :)
可以幫你產出各種隨機的東西\
我們來用用 `random.randrange()`,[用法點我](https://docs.python.org/3/library/random.html#random.randrange)
根據既有的知識,既然 random 是一個 object、randrange() 後面有括號、兩者之間還是一個點,那麼 randrange 就是 random 旗下的 method 了
<br/><br/>
簡單來說,如果要在 range(10) 中選一個整數,就用 `random.randrange(10)`
翻成中文就是
「手上有一個被 import 進來的 random object 了」
「現在要對我的 random object 使用 randrange」
「使用 randrange 時帶入 10,這樣它就知道我的範圍了」
<br/><br/><br/><br/>
:::spoiler 現在寫一個抽籤的程式吧
參考架構如下
* 一個變數(user input)代表「使用者輸入班上人數」
* 一個變數(user input)代表「使用者輸入要抽出的人數」
* 用一個 for loop 一次抽一個人,然後印出來
* 最後說抽籤結束<br/><br/>
寫出來之後想想看
1. 要怎麼讓最後一號也有被抽到的機會?
2. 萬一使用者輸入的「要抽出的人數」比「全班人數」多,怎麼辦?
3. 有辦法把 for loop 換成 while loop 嗎?
:::
<br/><br/>
------
現在來介紹另一個
```python
import time
```
[用法點我](https://docs.python.org/3/library/time.html)
常用的有 `time.sleep()`\
可以讓程式跑得不那麼快<br/><br/>
至於取得當下時間,我偏好使用另一個 **module**,[datetime](https://docs.python.org/3/library/datetime.html#module-datetime)
不過這個比較特別,在 `import` 的時候,我們會用
```python
from datetime import datetime
```
因為 `datetime` 本身是一個更大的 object,我們只有要用到它旗下的 datetime object 而已(可以理解成,對,它跟它旗下的 object 撞名
要叫出當下時間,可以用 `datetime.now()` 或 `datetime.today()`<br/><br/>
如果上面一開始不是寫 `from datetime import datetime`\
而是只有 `import datetime`\
這邊要叫出時間就要變成
```python
datetime.datetime.now() 或 datetime.datetime.today()
```
<br/><br/>
各種 module 的用法我們後面會再解釋\
簡單來說,第一個 datetime 是一個裝了很多模組的大資料夾,第二個則是我們要的模組\
`now()` 或 `today()` 是模組裡的功能\
我們透過 點. 來一層一層進入
<br><br>
:::spoiler `References`
function vs. method https://www.geeksforgeeks.org/difference-method-function-python/
:::
:::spoiler `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
:::
<br></br>
:::info
[BACK](https://hackmd.io/@lhsueh1/python101)
:::