Udemy課程:[100 Days Of Code(Dr. Angela Yu)](https://www.udemy.com/course/100-days-of-code/)
# Day 8 - Beginner - Function Parameters & Caesar Cipher
###### tags: `python` `Udemy` `100 Days Of Code`
2021.02.15(Mon.)~02.17(Wed.)
## ● 前言 / 心得
這堂課前半段都還算滿簡單的,基本上很快就能寫出來,不過到project的部分就花點時間去思考該怎麼設計,因此也更加放慢腳步,每一步都記錄下來,不只是自己的想法,也把老師的作法給記錄下來,感覺對於程式也會有更多方面的思考模式!
然後遇到一些常遇到也都常常忘記的東西,像是對字串每個字迴圈,可以直接對他用list(字串)把字串拆成每個單字,再利用for i in range(0,len(list(字串))),或者更簡單的直接for i in 字串就可以了!另外一個則是載入其他檔案,記得語法是from 檔案 import 檔案裏要的內容,大概是這樣,期待下一堂課!
## ● 上課筆記
## 0.code
[day-8-start-1](https://repl.it/@tina0915tw/day-8-start-1#main.py)
[day-8-end](https://repl.it/@tina0915tw/day-8-end#main.py)
[day-8-1-exercise](https://repl.it/@tina0915tw/day-8-1-exercise#README.md)
[day-8-2-exercise](https://repl.it/@tina0915tw/day-8-2-exercise#main.py)
[caesar-cipher-1-start](https://repl.it/@tina0915tw/caesar-cipher-1-start#main.py)
[caesar-cipher-2-start](https://repl.it/@tina0915tw/caesar-cipher-2-start#main.py)
[caesar-cipher-3-start](https://repl.it/@tina0915tw/caesar-cipher-3-start#main.py)
[caesar-cipher-4-start](https://repl.it/@tina0915tw/caesar-cipher-4-start#main.py)
## 1.functions用法
function的表達方式:
```python=
def my_function():
#Do this
#Then do this
#Finally do this
my_function() #呼叫函數
```
## 2.functions with inputs用法
```python=
def my_function(something):
#Do this something
#Then do this something
#Finally do this something
my_function(123) #呼叫函數
#此時這個函數裡的something就會等於123
```
* 重點整理:
> 
> | 名稱 | 內容 |
> | ---- | ---- |
> | Argument |The argument is the actual piece of data,that's going to passed over to this function when it's being called.|
> | Parameter | The parameter isthe name of that data,and we use the parameter inside the function to refer to it and to do things with it.|
>
## 3.Arguments(引數)
> 參考此[網站](https://qiubite31.github.io/2016/08/22/%E4%BD%8D%E7%BD%AE%E5%BC%95%E6%95%B8-Positional-Argument-%E8%88%87%E9%97%9C%E9%8D%B5%E5%AD%97%E5%BC%95%E6%95%B8-Keyword-Argument/)
>
Python函式參數所接收的引數(Argument),主要可以分成兩種,分別為位置引數(Positional Argument)和關鍵字引數(Keyword Argment)
1. 位置引數(Positional Argument)
```python=
def my_function(a,b,c):
#Do this a
#Then do this b
#Finally do this c
my_function(3,1,2) #呼叫函數
#代表a=3,b=1,c=2
```
2. 關鍵字引數(Keyword Argment
```python=
def my_function(a,b,c):
#Do this a
#Then do this b
#Finally do this c
my_function(c=3,a=1,b=2) #呼叫函數
#代表a=1,b=2,c=3
```
## 4.無條件進位/四捨五入/無條件捨去
> [day-8-1-exercise](https://repl.it/@tina0915tw/day-8-1-exercise#README.md)有用到
**記得一定要先「import math」!**
```python=
import math
```
1. 無條件進位:(記「天花板」ceil)
```python=
math.ceil(number)
```
2. 無條件捨去:(記「地板」floor)
```python=
math.floor(number)
```
3. 四捨五入:
```python=
round(number)
```
## 5.[day-8-2-exercise](https://repl.it/@tina0915tw/day-8-2-exercise#main.py)解釋
這題是要我們寫出一個function,可以幫我們檢查某個數字是否為「質數」。
* 所以要先知道怎麼判斷函數?
> 首先,我們都知道質數只能被「1」跟「自己」整除。也就是說,質數去除以「1」跟「自己」以外的數字時,都一定會有「餘數」!說到「餘數」,就該想到可以使用的modulus(取餘數,用「%」表示)。
>
> 因此第一步便是利用modulus來檢查這個餘數是否為0。
* 不過是甚麼東西的餘數呢?
> 所以接著第二步,就是要讓測試的數字去除以小於他自己本身的每個數字。
>
> 舉例來說:
>
> 這個數字是5的話,那我們就讓5÷2、5÷3、5÷4,然後去檢查這三個出來的餘數為多少,如果都為0,代表可以被2、3、4整除,那他就不是質數了,不過相反的,像是這裡用的範例數字5來說,5÷2、5÷3、5÷4皆會使餘數不等於0,都不能整除,也就是說5除了能被「1」跟「自己」整除而已,所以就能判斷5為質數。
* 老師的作法:
```python=
n = int(input("Check this number: "))
prime_checker(number=n)
def prime_checker(number):
is_prime = True #用來判斷現在狀態
for i in range(2,number):
if number % i == 0:
is_prime = False
if is_prime:
print("It's a prime number.")
else:
print("It's not a prime number.")
```
## 6.Ceaser cipher(凱薩密碼)
(這是這課要做的project)
***
### **一、[caesar-cipher-1-start](https://repl.it/@tina0915tw/caesar-cipher-1-start#main.py)**
第一個階段先做出一個可以讓使用者輸入一段字母,然後再輸入一個數字,而數字即是偏移量(shift,偏移多少數字,就代表偏移幾個字母)
> 舉例來說:
>
> 偏移量是3(shift=3)的時候,所有的字母A將被替換成D,B變成E以此類推。
>
> 如下圖所示:
> 
**1. 將一字串拆分為單個字母:**
> 關鍵字:list( )
這個常常忘記!
範例:
```python=
string="asdasd"
list(string) #['a', 's', 'd', 'a', 's', 'd']
```
**2. 找出陣列中某值的位置:**
> 關鍵字:index( )
參考資料:[Python List index() Method](https://www.w3schools.com/python/ref_list_index.asp)
範例:
```python=
fruits = ['apple', 'banana', 'cherry']
x = fruits.index("cherry") #2
```
**3. 其他:**
還有用到for迴圈、if...else、len( )
* 我的作法:
```python=
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
#TODO-1:
def encrypt():
#TODO-2:
listText = list(text)
cipher_text = ""
for i in range(0,len(listText)):
index = alphabet.index(listText[i])
index += shift
if index > 25:
index = index - 26
cipher_text += alphabet[index]
else:
cipher_text += alphabet[index]
print(f"The encoded text is {cipher_text}.")
#TODO-3:
encrypt()
```
* 老師作法:
不一樣的地方:
1.老師用了代入參數的方式
2.for loop的部分,老師直接對字串的每個字母做迴圈
3.index偏移過後,超出26個字母範圍的處理,老師是直接在alphabet字母陣列中的後方再加上一組a~z
```python=
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
#TODO-1:
def encrypt(plain_text, shift_amount):
#TODO-2:
cipher_text = ""
for letter in plain_text:
position = alphabet.index(letter)
new_position = position + shift_amount
new_letter = alphabet[new_position]
cipher_text += new_letter
print(f"The encoded text is {cipher_text}")
#TODO-3:
encrypt(plain_text=text, shift_amount=shift)
```
***
### **二、[caesar-cipher-2-start](https://repl.it/@tina0915tw/caesar-cipher-2-start#main.py)**
第一階段是加密(encode)的動作,到第二階段就要來新增解密(decode)了。想法其實就是第一階段反過來思考而已,基本上沒有太大的問題。
```python=
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
def encrypt(plain_text, shift_amount):
cipher_text = ""
for letter in plain_text:
position = alphabet.index(letter)
new_position = position + shift_amount
cipher_text += alphabet[new_position]
print(f"The encoded text is {cipher_text}")
#TODO-1:
def decrypt(plain_text, shift_amount):
#TODO-2:
cipher_text = ""
for letter in plain_text:
position = alphabet.index(letter)
new_position = position - shift_amount
cipher_text += alphabet[new_position]
print(f"The encoded text is {cipher_text}")
#TODO-3:
if direction == "encode":
encrypt(plain_text=text, shift_amount=shift)
elif direction == "decode":
decrypt(plain_text=text, shift_amount=shift)
```
***
### **三、[caesar-cipher-3-start](https://repl.it/@tina0915tw/caesar-cipher-3-start#main.py)**
第三階段則是要弄出一個新function叫做caesar( ),然後包含前面兩階段做的兩個function:encrypt( )跟decrypt( ),並且把最後if...elif弄掉,只需叫出一個caesar( )就好。
這裡有個特別更簡短的寫法,下面是我寫的:
```python=
if cipher_direction == "encode":
new_position = position + shift_amount
elif cipher_direction == "decode":
new_position = position - shift_amount
```
而老師的解決方法:
新位置(new_position)同樣都是把位置(position)加上偏移量(shift_amount),但是當要decode時,要偏移回來,因此讓他的偏移量(shift_amount)變成負的。
```python=
if cipher_direction == "decode":
shift_amount = shift_amount * -1
new_position = position + shift_amount
```
但是要注意如果用上面這個方法的話,if要丟到for loop外面,否則每次迴圈都會再乘以一次-1,就會變成負正負正交替下去。
* 完整作法:
```python=
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
#TODO-1:
def caesar(start_text, shift_amount,cipher_direction):
end_text = ""
if cipher_direction == "decode":
shift_amount = shift_amount * -1
for letter in start_text:
position = alphabet.index(letter)
new_position = position + shift_amount
end_text += alphabet[new_position]
print(f"The {cipher_direction}d text is {end_text}")
#TODO-2:
caesar(start_text = text, shift_amount = shift,cipher_direction = direction)
```
***
### **四、[caesar-cipher-4-start](https://repl.it/@tina0915tw/caesar-cipher-4-start#main.py)**
接著是最後的階段,第四階段。
這階段要處理的就是user experience improvement(使用者經驗改進)以及剩下的修改。
**1. import檔案**
> 關鍵字: from...import
現在我要載入art.py這個檔案中的logo。
作法:
```python=
from art import logo
print(logo) #已經載入了,就可以使用了!
```
**2. 處理:使用者輸入的字母過多或偏移量過大時**
對偏移量做modulus(%)來取得餘數
作法:
```python=
shift = shift % 26
```
**3. 當使用者輸入了number/symbol/space該怎麼辦**
所以先用if來判斷使用者輸入的字是否有在alphabet陣列中(也就是判斷是否為a~z其中之一),若不是的話則讓end_text去加上原本的字,不做變化。
作法:
```python=
for char in start_text:
if char in alphabet:
position = alphabet.index(char)
new_position = position + shift_amount
end_text += alphabet[new_position]
else:
end_text += char
```
**4. 完成後詢問使用者是否要再試一次**
最後一個修改。跑完一輪後,詢問使用者是否要再試一次,如果使用者輸入「yes」時,則整個程式要重新run一遍;若使用者輸入「no」,則print出goodbye並且結束程式。
> 這裡運用到了while loop,所以先思考while什麼樣的情況is true,可以再次執行呢?因此先設定一個變數should_continue = True。
>
> 接著再思考那甚麼時候不要再繼續呢?也就是當我們先詢問使用者是否繼續,而使用者答「no」的時候。
作法:
```python=
should_continue = True
while should_continue:
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
shift = shift % 26
caesar(start_text=text, shift_amount=shift, cipher_direction=direction)
restart = input("Type 'yes' if you want to go again. Otherwise type 'no'.\n")
if restart == "no":
should_continue = False
print("GoodBye ! ")
```
* 完整作法:
```python=
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
def caesar(start_text, shift_amount, cipher_direction):
end_text = ""
if cipher_direction == "decode":
shift_amount *= -1
for char in start_text:
#TODO-3:
if char in alphabet:
position = alphabet.index(char)
new_position = position + shift_amount
end_text += alphabet[new_position]
else:
end_text += char
print(f"Here's the {cipher_direction}d result: {end_text}")
#TODO-1:
from art import logo
print(logo)
#TODO-4:
should_continue = True
while should_continue:
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n")
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
#TODO-2:
shift = shift % 26
caesar(start_text=text, shift_amount=shift, cipher_direction=direction)
restart = input("Type 'yes' if you want to go again. Otherwise type 'no'.\n")
if restart == "no":
should_continue = False
print("GoodBye ! ")
```