# Python * Ref: [Method](https://www.learncodewithmike.com/2020/01/python-method.html) * Ref: [Inheritance](https://www.learncodewithmike.com/2020/01/python-inheritance.html) * Ref: [Class還沒看](https://www.brilliantcode.net/761/python-3-6-class/) * 名詞定義: object(物件), class(類別) ## Data tpye > 用`type`可以看型態 (e.g, type(0c10) = int) - int: 預設10進位 - 二進位: 0b10 -> (10)~2~ -> output: 2 - 八進位: 0o10 -> (10)~8~ -> output: 8 - 16進位: 0x10 -> (10)~16~ -> output: 16 - float: 10/3 = 3.333333 (但 10//3 = 3) - 在Java中 10/3 結果會變成3 - complex: a+bj - type(a+bj) = complex - string: - 判斷目標字串是否在來源字串裡: `targetStr in sourceStr` - targetStr = 'ple', sourceStr = 'apple' targetStr in sourceStr = True - 字串相連: `str1 + str2` 或 `str = ''.join([str1, str2])` - str1 = 'app', str2 = 'le' str1 + str2 = 'apple' - str = ''.join([str1, str2]) = 'apple' - str = ','.join([str1, str2]) = 'app,le' - str = 'xxx'.join([str1, str2]) = 'appxxxle' - str = "xxx".join([str1, str2]) = 'appxxxle' - 字串長度: `len(str)` - str = 'apple', len(str) = 5 - 重複字串: `str * n` - str = 'apple', n = 3 str * 3 = 'appleappleapple' - 數值轉字串: `str()` - i = 10, str(i) = '10' - 索引: `[-n]`代表`倒數第n個`元素 - str = 'apple' str[0] = 'a', str[-1] = 'e', str[-2] = 'l' - 字串切片(Slice): `[fromInclude : toExclude]` - str = 'apple' str[0:3] = 'app', str[2: ] = 'ple', str[ :2] = 'ap', str[-4:-1] = 'ppple' - 字串切片2: `[fromInclude : toExclude : stepSize]` - str = 'qazxcv' str[0:3:2] = 'qz', str[::-1] = 'vcxzaq' - 轉大寫: `upper()` - str = 'apple', str.upper() = 'APPLE' - 轉小寫: `lower()` - str = 'APPLE', str.lower() = 'apple' - List (串列): `[]`字樣, 有序(即可以用L[index]), 變動長度, 每個元素以逗號分隔, mutable - 新增在最後位置: `.append()` - 新增多個元素在後: `.exend()` - 提取並移除最後一個元素: `.pop()` - 移除最後一個元素: `.remove(element)` - 移除特定範圍: `del list[fromInclude : toExclude]` - 插入元素: `.insert(index, element)` - 反轉: `.reverse()` - 升序排序: `.sort()` - 降序排序: `.sort(reverse=True)` - 複製: `.copy()` > 在串列複製時, **不要使用 L~2~ = L[:]**, 因為這樣的assign是做`參考之複製`, 當L~2~中的元素被重新assign成其他值, 原本L中相對應位置的元素之值也會隨之更動 ``` L = [1,2,3] L.append(9) # L = [1,2,3,9] L.extend([5,6,7]) # L = [1,2,3,9,5,6,7] L.pop() # L = [1,2,3,9,5,6] L.remove(1) # L = [2,3,9,5,6] del L[0:2] # L = [9,5,6] L.insert(1,7) # L = [9,7,5,6] L.reverse() # L = [6,5,7,9] L.sort() # L = [5,6,7,9] L.sort(reverse=True) # L = [9,7,6,5] L[:] = [] # L = [] ``` - Set (集合): `{}`字樣, 無序(沒有s[index]用法), 元素不重複(沒有`*`複製元素用法, `[:]`片段用法, `+`用法), mutable - 建立空集合: `xxx = set()` 或 `xxx = {}` - 聯集: `setA | setB` 或 `setA.union(setB)` - 聯集並更新(setA): `setA.update(setB)` - 交集: `setA & setB` 或 `setA.intersection(setB)` - 交集並更新(setA): `setA.intersection_update(setB)` - 差集: `setA - setB` 或`setA.difference(setB)` - 差集並更新(setA): `setA.difference_update(setB)` - XOR: `setA ^ setB` 或 `setA.symmetric_difference(setB)` - XOR並更新(setA): `setA.symmetric_difference_update(setB)` - 新增在第一個位置: `.add(element)` - 移除元素: `.remove(element)` - 提取並移除第一個元素: `.pop()` - 複製: `.copy()` - 清空: `.clear()` ``` setA = {1,2,3} setB = {2,3,4} print(setA & setB) # {2,3} print(setA | setB) # {1,2,3,4} print(setA - setB) # {1} print(setA ^ setB) # {1,4} setA.add(9) print(setA) # {1,2,3,9} setA.remove(3) print(setA) # {1,2,9} setA.clear() print(setA) # set() ``` - Tuple (序對): `()`字樣, 有序(即可以用L[index]), 每個元素以逗號分隔, immutable ``` ref: https://openhome.cc/Gossip/Python/TupleType.html t = ([1, 2], [3, 4]) t[0] = [10, 20] # invalid t[0][0] = 10 # valid l = t[0] l[0] = 10 l[1] = 20 print(t) # ([10, 20], [3, 4]) ``` - 操作(對於tuple序對, list串列, set集合): - swap: `x, y = y, x` - 多重assign: `1, 2, 3 = x, y, z` - 擴充多重assign(Python3): `*`字樣 - x, *y = [1, 2, 3, 4, 5] x = 1, y = [2, 3] - x, *y, z = [1, 2, 3, 4, 5] x = 1, y = [2, 3, 4], z = 5 - Dict (字典): 存key(鍵) & value(值), mutable - 建立字典: `xxx = {key1: name1, key2: name2}` 或 `xxx = dict(key1 = name1, key2 = name2)` - 找特定鍵之值: `.get(key)` - 新增鍵&值: `.update({newKey: newValue})` - 移除特定鍵&值: `.pop(key)` 或 `del xxx[key]` - 取所有鍵&值(用tuple儲存): `.items()` - 取所有鍵: `keys()` - 取所有值: `values()` ``` d = {'Ricky': 31, 'RickyLR': 32} # 31 print(d.get('Ricky')) # None print(d.get('Richard')) #YourReturnMsg print(d.get('Richard', 'YourReturnMsg')) # same as d.pop('Ricky') del d['Ricky'] # {'RickyLR': 32} print(d) d.update({'RickyLLR': 33}) # {'RickyLR': 32, 'RickyLLR': 33} print(d) # dict_items([('RickyLR', 32), ('RickyLLR', 33)]) print(d.items()) # dict_keys(['RickyLR', 'RickyLLR']) print(d.keys()) # dict_values([32, 33]) print(d.values()) ``` ## If/For/While/Try/Raise - If/Else if/Else 陳述句: - 語法: `if xxx:` `elif xxx:` `else:` - 三元運算子(C++/Java):`xxx = y if zzz else vvv` - For-loop: 可迭代access字串, list, set, tuple, dict - 語法: ``` 1. for xxx in range(fromInclude, toExclude, stepSize): 2. # list L = [1,2,3,4] for i in L: print(i) 3. # set s = {1,2,3,4} for i in s: print(i) 4. # tuple t = [(1,2), (4,3)] for (x,y) in t: print(x,y) 5. # dict d = dict(Ricky= 31, RickyLR= 32) for (key, value) in d.items(): print(key, value) ``` - For 包含式(Comprehension): 跟Matlab某些用法很像 ``` L = [1,2,3,4] j = [i**2 for i in L] # j = [1,4,9,16] ``` - While: - 語法: `while xxx:` - Try: - [這篇講得很有趣!](https://ithelp.ithome.com.tw/articles/10231653) - 語法: ``` 1. try: xxx 2. try: xxx except 什麼情形: 做相對應處理 3. try: xxx except 什麼情形: 做相對應處理 else: yyy <- 例外沒發生做的事情 finally: zzz <- 無論是否有例外都會做的事情 # 手動丟異常 4. try: xxx if yyy: raise zzz except zzz ``` ## Def - 語法: ``` #function需要讀入一個參數 1. def functionName(x): #function讀入不定數量的參數 2. def functionName(*x): def sum(* num): total = 0 for n in num: total += num return num print(sum(1)) # 1 print(sum(1,2)) # 3 print(sum(1,2,3)) # 6 ``` - 可以定義區域函式(Local function) - 執行functionName時, 會執行到內部區域的函式anotherFunName, 他不用像C++把anotherFunName提出去functionName ``` def functionName(xxx): def anotherFunName(zzz): zzz anotherFunName(xxx) ``` ## 看不太懂的 [lambda](https://openhome.cc/Gossip/Python/LambdaExpression.html) [變數範圍](https://openhome.cc/Gossip/Python/VariableScope.html) [yield](https://openhome.cc/Gossip/Python/YieldGenerator.html) ## NumPy - import模組: `import numpy as np` - 建立陣列: `Arr = np.array([xxx])` - 陣列維度: `Arr.ndim` - 陣列資料型別: `Arr.dtype` - 陣列形狀(幾x幾...): `Arr.shape` - 改變陣列形狀: `Arr.reshape([x, xx, ...])` - row數不知道: `Arr.reshape(-1, x)` - 零陣列: `Arr.zeros([x, xx, ...])` - 一陣列: `Arr.ones([x, xx, ....])` - 陣列切片: `Arr[YourSpeCondition]` - 加總/最小值/最大值: `Arr.sum(axis = n)` `Arr.min(axis = n)` `Arr.max(axis = n)` - x軸加總: `Arr.sum(axis = 0)` - y軸加總: `Arr.sum(axis = 1)` - 元素相加: `np.add(Arr1, Arr2)` - 元素相減: `np.subtract(Arr1, Arr2)` - 元素相乘: `np.multiply(Arr1, Arr2)` - 元素相除: `np.divide(Arr1, Arr2)` - 內積: `np.dot(Arr1, Arr2)` - 變一維: `np.flatten()` ``` np1 = np.array([[1, 2, 3, 4], [6, 7, 8, 9]]) print(np1.ndim, np1.shape, np1.dtype) # 2 (2, 4) int64 np2 = np1.reshape(-1, 1) # np2的size為(8 rows, 1 col) np3 = np2[np2 > 5] # np3 = [6, 7, 8, 9] print(np1.sum(axis = 0)) # [7, 9, 11, 13] print(np1.sum(axis = 1)) # [10, 30] np4 = np1.flatten() # [1, 2, 3, 4, 5, 6, 7, 8, 9] ``` ## OpenAI - GYM ## Method ### Instance Method (實體方法) - 利用self參數存取/更動object屬性 - 呼叫實體方法時, compiler會傳入物件, 使self參數指向該object - 不能透過class呼叫實體方法, 如Rank.show() ### Class Method/Factory Method (類別方法/工廠方法) - 會有 '@classmethod' 的裝飾詞 - cls參數指向class; self參數指向object - 只能更動class狀態, 不能更動object狀態 - 常用於產生object ### Static Method (靜態方法) - 會有 '@staticmethod' 的裝飾詞 - 可接受任意參數, 但無法更動class & object狀態(避免新人更動到其中一個的狀態) - 可以由object或class呼叫 如class定義如下 ``` class Rank: # class attribute rk = 1024 # constructor def __init__(self, rk): self.rk = rk # instance method def rankUp(self): self.rk += 1 def show(self): print(f"Your current rank is {self.rk}.") # class method @classmethod def rankUpFromClassMethod(cls): print(f"Your current rank is {cls.rk}.") @classmethod def chiefEngineer(cls): return cls(33) @classmethod def assistantManager(cls): return cls(34) # static method @staticmethod def show2(opstr): print(f"Your input string is {opstr}.") ``` 則 ``` >>> Ricky = Rank(100) >>> Ricky.show() (output)>>> Your current rank is 100. >>> Ricky.rankUp() #透過物件呼叫 >>> Ricky.show() (output)>>> Your current rank is 101. >>> Rank.rankUpFromClassMethod() #透過類別呼叫 (output)>>> Your current rank is 1024. >>> ce = Rank.chiefEngineer() >> ce.show() (output)>>> Your current rank is 33. #透過類別建立 >>> ce2 = Rank(33) >>> ce2.show() (output)>>> Your current rank is 33. #透過constructor建立 >>> Ricky.show2("Hello") (output)>>> Your input string is Hello. #透過物件呼叫 >>> Rank.show2("Hello2") (output)>>> Your input string is Hello2. #透過類別呼叫 ``` 如要更改class屬性, 可透過下列兩個方法 ``` class Rank: # class attribute rk = 1024 # Method 1 def change(self): self.__class__.rk = 32 # Method 2 def change(self): self.rk = 32 ``` ## Inheritance ### Concept - 繼承父類別公開的屬性&方法 ``` class Women(Rank): def showW(self): print("WONEN") def conflict(self): print("CONFLICT-WOMEN") class Man(Rank): def showM(self): print("MAN") def conflict(self): print("CONFLICT-MAN") ``` 則 ``` >>> HBY = Man(999) >>> HBY.show() (output)>>> Your current rank is 999. >>> HBY.showM() (output)>>> MAN >>> Rita = Women(888) >>> Rita.show() (output)>>> Your current rank is 888. >>> Rita.showW() (output)>>> WOMEN ``` ### Method Overwriting (覆寫父類別方法) ``` class Man(Rank): def showM(self): print("MAN") def show(self): print("overwritten by Man class") ``` 則 ``` `>>> HBY.show() (output)>>> overwritten by Man class ``` 如要執行父類別的方法, 用`super().xxx` ``` class Man(Rank): def showM(self): print("MAN") def show(self): super().show() print("overwritten by Man class") ``` 則 ``` >>> HBY.show() (output)>>> Your current rank is 999. (output)>>> overwritten by Man class ``` ### Multi-level Inheritance (多層繼承) ``` class HumanM(Man): pass ``` 則 ``` >>> HBY = Human(999) >>> HBY.show() (output)>>> Your current rank is 999. (output)>>> overwritten by Man class ``` ### Multiple Inheritance (多重繼承) ``` class Human(Man, Women): pass ``` 則 ``` >>> HBY = Human(999) >>> HBY.showW() (output)>>> WOMEN >>> HBY.showM() (output)>>> MEN ``` 特別注意到, 如要進行多重繼承, 要檢查是否有method名稱相同的, 如Man跟Women裡都有conflict(), 則會發生 ``` >>> HBY.conflict() (output)>>> CONFLICT-MAN ``` 原因是compiler會從左到右去看, 是否有method名稱叫做conflict(), 如有則執行, 並停止後續之檢查