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 ``` * 重點整理: > ![](https://i.imgur.com/46t6jAf.jpg) > | 名稱 | 內容 | > | ---- | ---- | > | 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以此類推。 > > 如下圖所示: > ![](https://i.imgur.com/ddW3hc1.jpg) **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 ! ") ```