我們前一篇介紹了安裝、基本語法以及資料型態,這一天我們就是銜接上一天來做進階介紹,
理論上在經過這兩天之後你就可以出去大喊我會 python 啦 (會hello word 也是會啊),
所以把今天好好吸收之後,我們就可以直接來 AI 的部分惹。
在開始介紹Python迴圈之前,
先來說明一個在執行迴圈時常用的range()方法,
主要用來幫我們產生數列,語法如下:range(起始值,結束值,遞增(減)值)
使用說明:
可以針對Iterable(可疊代的)物件來進行讀取,
像是Python內建幾個常用的Iterable物件,
例如:String(字串)、List(串列)、Tuples(元組)、Dictionary(字典)等。
Python for-loop的語法如下:
for item in iterable:
statement
枚舉 enumerate()
在語法中,
in 的後方就是 for-loop 要讀取的目標物,
這個目標物的為Iterable (可疊代的)物件,一次讀取一個元素,
然後用 item (自訂變數名稱)來接收每次讀取到的元素,執行區塊中的運算。
注意for-loop的結尾需加上冒號 ( : ) 及區塊中的運算式要有相同的縮排,
範例如下:
在範例中,For-loop的讀取目標物為一個字串,每一次讀取一個字母,
並且用word變數來接收,執行print()輸出方法。
while 語法用於循環執行程序,意思是在某特定條件下,
循環執行該項程序,以處理需要重複處理的相同任務。
概念如下:
while 判斷條件():
執行語句()
可以理解成,當判斷條件為真才執行語句 ,
這邊的話,提供一個動圖方便理解概念,
接下來就是範例介紹:
當我們輸入下述程式碼,
a = 1
while a <= 10:
print(a)
a = a+2
實際運行就會得到結果如下
1
3
5
7
9
解釋上,首先宣告 a = 1 , 然後當 a 小於等於 10 時 ,輸出 a 同時將 a+2 ,
這樣整串程式碼會重複執行至 a 不再小於等於 10 。
在這樣的過程中,我們可以設想到一個狀況,
如果判斷永遠等於 True ,那會發生什麼狀況呢?
首先我們輸入該程式碼,
a = 1
while a == 1:
print(a)
會得到結果是無數的 1 ,這時就需要 control + c 來強制中斷該程序。
while 與 For-Loop 的部分還有判斷用法,
以 while 來舉例:
a = 1
b = 2
while a == 1:
print(a)
else:
print(b)
這時就會回傳 a ,假設 a 不是 1 ,才會回傳 b 。
Python 語言中提供了 if 、 else 、 elif 這三種語法來協助各種條件判斷和流程控制。
Python 一行一行執行的,所以當我們想要所寫的程式在某些條件下跳過某幾行敘述,就可以使用條件判斷。
也就是說,如果要讓程式可以自動檢查所處理資料的內容,
而且根據資料內容來決定是否執行某一個敘述或指令,那就需要用到條件判斷式來控制流程。
程式在進行的過程,需要根據某個條件來決定是否執行接下來的動作時,
可以透過:
if abc == True:
print("hello world")
來進行條件判斷,如同字面上的意思,當宣告的變數等於"真"時,
就會輸出自定義的訊息,如果當宣告的變數或條件不相等時,
便會跳過這個判斷直接往下執行。
當今天我們要追求非真及否的狀況下,
就會運用到:
if abc == True:
print("hello world")
else abc == False:
print("This is False")
來進行條件判斷,如同字面上的意思,當宣告的變數等於"真"時,
便會輸出 hello world 如果等於"否",就會輸出 This is False,
但有些情況下我們只想要宣告的變數等於特定值,如果等於其他值便給予統一的回覆,
則可以這樣運用:
if abc == True:
print("hello world")
else:
print("This is False")
這樣只有當宣告的變數等於"真"時,才會給予 hello world 的回覆,如果變數是其它任何數值,
都會給予 This is False 。
有的時候需要判斷的可能狀況有很多種時,便會需要用到這個狀況,
例如:
if abc == 1:
print("number is 1")
elif abc == 2:
print("number is 2")
else:
print("number")
如同上述字面上的意思,當數值為特定的時後會給予定義的數值,
如果都不是就單純輸出 number 字串。
當我們要在判斷條件中安排更進一步的判斷條件時,就需要用到巢狀結構了。
所謂的巢狀 if 敘述是指在 if-else 敘述當中,還有另一組 if-else 敘述,
例如:
id = "Andy"
age = 20
if age < 10:
print("not Andy")
elif id == "Andy" and age <= 20:
if age == 20:
print("is Andy")
elif age == 18:
print("Andy age not 18")
elif age == 16:
print("Andy age not 16")
elif age == 14:
print("Andy age not 14")
else:
print("not Andy QQ")
上述判斷當 id 等於 Andy 且 age 等於 20 時,才是 Andy 。
例外處理 (exception handling) 是利用 try 、 except 、 finally 及 else 來進行判斷,
當今天我們已經得知執行 1 除以 0 的情況,會得到 ZeroDivisionError: division by zero
這個錯誤回報,所以我們假定一個方法如下:
try:
print("程式運行至點位0")
result = 1 / 0
print("程式運行至點位1")
except Exception as e:
print("錯誤信息",e)
print("程式運行至點位2")
運行完後會我們可以得到,
從上述程式碼運行結果可以得知,try expect 語法無論如何都會先從 try 語法一句一句執行,
假設遇到 error 才會中斷,從 expect 再繼續執行,
上段程式碼我們先輸出 " 程式運行至點位0 " ,然後當它執行完 result = 1 / 0 的語句時,
便會中斷沒有繼續往下執行輸出 "程式運行至點位1" 。
因為 result = 1 / 0 單獨運行時我們已經得知它是個錯誤的語法,會回傳 ZeroDivisionError ,
所以我們 except Exception 是 error 的時候,我們輸出錯誤訊息 e ,且繼續輸出運行點位 2。
所謂例外 (exception) 是指已知有可能發生的錯誤 (error) ,像是開啟檔案,檔案卻不存在,
或除數為 0 等等的情況。
透過這樣的簡單運用可以得知,
在做個簡單的程序判斷來更充分了解上面四段的意思,
透過輸出可以得知由於 try 裡面的語法有錯誤所以程式碼往 except 繼續執行,
且由於有錯誤不會執行 else ,最後執行 "無論有無錯誤" 都會執行的 finally 。
列表推導式 (list comprehension) , 可以用英 文List Creation from For Loop 來理解,
用以創建具有篩選能力的迴圈,其結果存為 列表 (list)。
說起來很像繞口令的廢話,但實際上能提供的效用卻非常大,
例如一般情況下新增資料進入一個預設好的列表:
list1=[]
for i in range(10):
list1.append(i)
print(list1)
上段程式碼會得到結果為 : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
但我們可以透過一句程式碼:
[i for i in range(10)]
便得到一樣的結果 : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
這個用法便為列表推導式,列表推導式並不是什麼特別的技術,它只是一種創建列表的簡潔方法,目的是為了讓大家寫程序時更方便更快捷,寫出更簡潔的程式碼。
同樣,如同一般程序,邏輯程序的結果存成 List ,所以我們可以透過語法的編寫來取得我們想要的 List,
[ i*i for i in range(10)]
將 for i in range(10) 的 i*i
來得到 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
透過一個練習來更加明白列表推導式的用法:
僅修正以下程式第4行,來使輸出結果為 [2, 4, 6, 20, 20]。
原先的程式碼我們可以得知, for i in bx 且 當 i % 2 > 0,
我們將 list 透過枚舉 ( enumerate ) 的方式,來得到它的 key 跟 value ,
list 的第 0 筆資料是 1 ,所以 0 是 key、1 是 value,以此類推,
觀察可得知列表中數值 2 , 4 , 6 位於 key , 1 , 3 , 5 的位址,
所以我們將 i (也就是 key ) %2 只要大於 0 便是 key 為奇數的位址,
再將 bx[i] 存進 list 便能得到我們想要的 [2, 4, 6, 20, 20]
如果覺得上述很繞口很難理解的話,用另外一種方式呈現來看:
原本的列表 bx 應該是 [1,2,3,4,5,6,20,20,20,20] ,
這些數值分表位於列表中的位址是:
[1,2,3,4,5,6,20,20,20,20]
0 1 2 3 4 5 6 7 8 9
可以得知題目的 [2, 4, 6, 20, 20] 分別位於列表中的位址 1,3,5,7,9
只需要將 key 除以 2 餘數大於 0 的儲存即可。
函數是預先建構好的可重復使用的,用來實現單一或相關聯功能的程式碼,能提高應用的模塊性,
和程式碼的重複利用率。Python 本身提供了許多內建函數,比如 print(),但也可以自己創建函數,這被叫做用戶自定義函數。
函式以 def 關鍵字定義,並以 return 將結果輸出。
一個函式只應該做好一件事情,太複雜拆開減少耦合,引數原則至多讓使用者輸入 2 個,其他引數都有預設值,引數為區域變數,計算結果透過 return 傳出。
好,上述應該講的非常文言,還是透過實際編寫來了解狀況:
首先我們定義一個函式叫做 add_number 且提供兩個變數 number1 , number2 供使用者自定義輸入,函式內進行邏輯運算,將 number1 + number2 的結果存為 Ans 且最後回傳。
如果函式結尾我們沒有以 return 敘述回傳,輸出將為空,意思就是函式處理的結果不會傳出來,
而函式內的 Ans 為區域變數,也就是在其他函式或函式外無法引用這個 Ans 。
在上圖的程式碼中可以看到,我們輸出函式 test 的結果為 1 ,但我們要單獨輸出 local 這個變數卻顯示尚未被定義,這就是因為我們只有將 local 設為函式 test 內的變數,
而在上圖的程式碼中我們可以看到,當 local 在函式外時無論函式內外都可以成功呼叫到這個變數,
那我們該如何將區域內的變數設為全域變數呢?
我們可以透過在宣告變數前先使用 global 這個方法將 local 預先設定為全域變數,
如此的話無論函式內外都可以成功呼叫。
在函式中我們常常可以見到 *args 及 **kwargs ,那他們分別代表甚麼意思呢,
首先來看看範例:
在上圖程式碼中可以看到我們將函式的可引入變數設成 *args,這個數值可透過使用者自定義輸入,
透過 * 收集的引數會被放到一個元組 (tuple)中,所以我們可以使用 for 迴圈來對它進行迭代。
使用 *args 的好處是我們當今天不確定預先輸入至函式的變數有多少時,
我們可以透過這個方法來避免輸入至函式的變數比預先設定的多,導至報錯。
那這邊就會疑問啦,那 **kwargs 呢,再來看新的範例:
這邊我們將函式的引入變數設成 (name="阿柴",age="21"),它會自己把它拆開變成 dict 格式,
那是不是好像懂了什麼 ?
概括的說一個 * 號類似於將資料蒐集存成 turple ,兩個 * 號則是蒐集完並且存成 dict,
那這樣的運用便十分得宜了,我們可以這樣用,
這邊就可以得知,我們第一個引入變數 0 被 money 接走了,多餘的則是被 args 接走,
而當我們引入變數是類似宣告較為具名者時(Ex:abc=2),它則會被 kargs 接走。
唯一要注意的是,* 一定要在 ** 的前面,而呼叫函式時有名字的也一定要在沒名字的後面。
這種的寫法通常會在裝飾器時使用,讓裝飾器可以接受參數數量不同的函式。
函式裝飾器又叫做 Decorator 也稱為語法糖,因為 Python 的函式也是物件,
所以可以達成用函式做為一個引數引入另一個函式,而裝飾器提供了簡潔的方式處理函式的傳入。
我們將 Decorator 設定成一個函式的名稱,裡面再包含了一個實際上想要提供功能的函式,
也就是外面的函式實際上只給予名稱,內層的函式才是給予功能,
再將它用小老鼠 @ 加在你想要提供的函式上面,便能給予一個函式更多的效果。
那其實流程上來說能夠看見,實際上在進入 age 函式之前它就已經進去 Decorator 函式裡面了,
由於我們 Decorator 裡面輸出 "我是阿柴" 之後便呼叫了 age 這個函數引數,
所以會先輸出 "我的年紀是21歲喔" 才輸出 "謝謝大家",
由此可知裝飾器的可操控性非常高,可以透過自己對於想要達到的目的來自由定義,
語法糖是 python 非常好用的功能,因為它能為每個程式碼來提供特一功能的函式,
避免函式重複撰寫,造成空間的浪費以及程式碼的雜亂,也易於後續的維護或者程式碼更改。
首先我們在一般定義一個函式的時候,應該是長成這樣的,
def add(a,b=1):
ans = a + b
return ans
但 Python 提供我們另外一種方式去定義函式,也就是 lambda ,
那它法其實很獨特,我們要定義匿名函式的話,需要這樣,以上面的函式為例子,
test_lambda = lambda a ,b=1 : a+b
注意到,它其實跟一般的語法很相像,
不過它在等號的右方是直接宣告 lambda 然後給予兩個參數 a b ,
然後在 : 符號後面定義函式應有的運算邏輯,
但這不是 lambda 的單一用法而已,
test2_lambda = lambda x: "數字是1" if x = 1 else "數字不是1"
我們可以透過這樣的方式,來達到判斷式的效果。
所以可以理解,在撰寫 Lambda 函式時,包含了三個部分:
參數清單也就是 Lambda 函式的傳入參數,可以有許多個,用逗號分隔。
而運算式則是針對傳入參數來進行運算,只能有一行運算式,不像一般函式可以有多行邏輯。
Lambda 函式支援 IIFE (immediately invoked function expression) 語法,意思是利用 function expression 的方式來建立函式並且立即執行它,語法如下:
(lambda parameter: expression)(argument)
那看到上面那串英文應該會感覺很疑惑,那是啥,
其實很簡單,我們這樣測試,
a = 1
print(lambda a:print(a))
<function <lambda> at 0x000001EFAE7EC0D8>
我們在運行上面 print(lambda a:print(a)) 會知道,
當Lambda函式經定義後,沒有進行呼叫的動作,
它會回傳一個 function object 且包含了記憶體位址,
如果我們想要印出值則可透過上面說的的IIFE語法進行呼叫,也就是:
(lambda a:print(a))(a)
就可以得到結果 a = 1 了。
這樣比較下來 lambda 與一般函式的差別在於,
補充一下,上面提到 IIFE 語法 全名為 Immediately Invoked Functions Expressions,
指的是可以立即執行的 Functions Expressions 函式表示式,中文多譯為立即(執行)函式。
在 python 應用中,讀取檔案或寫入檔案,是基礎中的基礎,也是不可或缺的技術,
因為我們有各種需求須將結果或過程寫入特定檔案以供使用者瀏覽,
那接下來就是介紹如何寫入各種檔案類型,
使用 open("檔案","模式") 的開啟文件
常用的模式有以下幾種:
打開之後當然是要讀取,所以我們在打開的時候通常會這樣撰寫,
filedata = open("檔案","模式")
接下來再以 .read 的方式回傳檔案內容
filedata.read()
寫入的話也十分簡單,透過以下方式,
filedata.write(string)
便可直接寫入,不過在程式結尾都必須加上一個 .close() 來做為結束。
在讀寫 json 檔之前,有必要先了解一下何謂 json ?
根據維基百科的說明,json 的全名是(JavaScript Object Notation,JavaScript 物件表示法),
是一種資料格式,並且支援多種程式語言,它的資料格式有2種:
物件以(key-value)的方式儲存,很像是python裡的字典,
例如說 {"Name": "阿柴", "age": 21} 便是一個物件的例子,
不過 json 的 key 值只能是文字, {10: "age"} 就是錯誤的例子,
!!! 注意json的字串是雙引號 !!!
如果在 python 中想要引用 json 模組,
需先寫上 import json 作為引入,
在模組中,我們要記兩個函數 dumps 與 loads ,
接下來來做幾個例題,
dumps 的部分
data = {'dog':'阿柴','age':21}
ans = json.dumps(data)
print(ans)
loads 的部分
data = '{"dog":"阿柴","age":21}'
ans = json.loads(data)
print(ans)
不過 python 內的字典是無序的資料,
若在 dumps 函數內加入參數 sort_keys = True,
可以將轉成 json 的格式的物件資料依 key 值排序,
import json
data = {'蔡鷹文':15, '韓國瑜珈老師':20, '宋楚瑜清芳': 10, '阿柴': 60, '美國瑜': -3}
ans1 = json.dumps(data)
ans2 = json.dumps(data, sort_keys = True)
print("未排序:", ans1)
print("排序後:", ans2)
有同學會好奇,上面這樣中文有亂碼怎辦,
這時候就要加上 ensure_ascii = False ,也就是,
ans1 = json.dumps(data,ensure_ascii=False)
就可以成功輸出了,介紹完這兩個方式後,該來讀寫檔案了,
在 python 中用來讀寫檔的語法為 with...open,我們可以透過它來,
寫檔
import json
data = {'蔡鷹文':15, '韓國瑜珈老師':20, '宋楚瑜清芳': 10, '阿柴': 60, '美國瑜': -3}
file = 'data.json'
with open(file, 'w') as obj:
json.dump(L, obj)
讀檔
import json
file = 'data.json'
with open(file, 'r') as obj:
data = json.load(obj)
print(data)
注意啦 json 檔讀檔進來後就是 python 的字典型態,而非字串ㄛ。
今天結束之後,一樣送大家一首歌,林宥嘉 傻子 (我不是說他傻子,是他的歌名就是傻子)
https://www.youtube.com/watch?v=xi6wOaZ61-U&list=PLZ_d6NX2sE80hOIrDy5J6vaCS53vj0oo7&index=14&ab_channel=%E8%8F%AF%E7%A0%94%E5%9C%8B%E9%9A%9B