# 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(), 如有則執行, 並停止後續之檢查