---
# System prepended metadata

title: Python Basic fundamental
tags: [python]

---

# Python Basic fundamental

###### tags: `python`

---
>
>* **本文內容為“Tibame快速闖關Python語法世界，程式實作不頭痛”為主，版權為issac所有，本文僅做筆記用途，非商業用途**
> 
>*  **本篇圖片部分出自“Tibame快速闖關Python語法世界，程式實作不頭痛”課程內容講義**
>
---

# :memo: Introduction
## 1. Python特色
- 可讀性高
- 跨平台
- 豐富第三方套件
- 直譯式語言
- 腳本語言
- 膠水語言
## 2. python生態系
![](https://i.imgur.com/Zhaif6Q.png)


# :memo: Principle of Operation
## 1. Python keyword
![](https://i.imgur.com/33Q4RvF.png)

## 2. Python Identifier
Identifier命名可區分不同名稱：
- 變數(Variable) 
- 函數(Function)
- 類別(Class)

Identifier命名規則
- 由 A-Z, a-z, 0-9, _所組成
- 第一字元不可為0-9
- 大小寫有區別
- 不要使用keyword命名

Identifier命名偵測是否有效

```python=
print("abc".isidentifier()) #True
print("99a".isidentifier()) #Flase
```

Identifier命名格式
- snake_case(ex: my_cat_name, my_cat_age)
- lowerCamelCase(ex: myCatName, myCatAge)
- UpperCamelCase(ex: MyCatName, MyCatAge)
- CAPITZLIZE(ex:PI,HOSTNAME)
## 3. Python Literals
**1. Literals為Python內建給予變數與常數的原始資料**
String literals   :   "halo" , '12345'
Int literals   :   0,1,2,-1,-2
Long literals   :   89675L
Float literals   :   3.14
Complex literals   :   12j
Boolean literals   :   True or False
Special literals   :   None
Unicode literals   :   u"hello"
List literals   :   [], [5,6,7]
Tuple literals   :   (), (9,),(8,9,0)
Dict literals   :   {}, {'x':1}
Set literals   :   {8,9,10}

**2. Numeric Literals (進位)**
EX:數字10,11
Decimal (十進位): 10, 11
Binary (二進位): 0b1010, 0B1011
Octal (八進位): 0o12, 0O13
Hexadecimal (十六進位): 0xa, 0XB

**3. 逃脫字元**
![](https://i.imgur.com/lk8QPgw.png)

## 4. Python Variable
**定義:用來儲存數值而被保留之記憶體**
![](https://i.imgur.com/1KBibBb.png  =312x146)

**Object (物件)**
變數從memory找到對應之物件提取其內容
![](https://i.imgur.com/eZAiNGD.png)

其中包含id、type、value
- identity(id):回傳此物件在memory中的位置
- type:物件之型別
- value:物件內之值
![](https://i.imgur.com/7PLros4.png)

**動態類型**
Python為動態類型語言，可自動偵測變數之型別
C/Java為靜態類型語言，需要先指定變數型別

**命名規則**
- 只能透過英文大小寫(A-Z,a-z), 數字(0-9), 底線(_)
- 不能用數字作為開頭
- 區分大小寫
- 底線(_)開頭
## 5. Python Operator
- Arithmetic Operator: ==+, -, *, /, %, **, //==
:::info
:bulb:Hint: %表示餘數，//表示商
:::
- Comparison Operator: ==\==, !=, >, <, >=, <\===
- Assignment Operator
![](https://i.imgur.com/R0fFy4y.png =500x)
- Logical Operator: ==and, or, not==
- Membership Operator: ==in, not in==
![](https://i.imgur.com/tdukjtC.png =200x)
- Identity Operator: ==is, is not==
![](https://i.imgur.com/DOsXSMH.png =400x)
- Bitwise Operator: ==&, |, ^, <<, >>==
&: AND(Both True=>True, Other=>False)
|: OR(Both False=>False, Other=>True)
^: XOR(True False=>True, Other=>False)
<<, >>:Shift Bit
![](https://i.imgur.com/amihri7.png =400x)
![](https://i.imgur.com/eg7wS2p.png =300x)

- 運算優先順序
![](https://i.imgur.com/VsqjhzO.png)


# :memo: Data Types
## 1. Numeric Type (int, float, complex)

| int     | float    |complex   |
| --------|----------|----------|
| 5       | 0.0      | 5+3j     |
| 22      | 22.5     | 5.j      |
| -3      | -3.89    | -3.89j   |
| 0b1010  | -3.      | .3j      |
| -0b1011 | 18.3e+9  | 18.3e+9j |
| 0x220   | -18.3e+9 | 18.3e-9j |

## 2. Boolean Type (bool)

Boolen only **True** or **False**
![](https://i.imgur.com/DzDj7RJ.png =300x)

## 3. Sequence Type (str, list, tuple)
### **string**
Imutable
#### 1. 常見string函數
```python=
s = "Surprise"
s2 = "MotherFucker"
print(s[0])          #S
print(s[4:])         #rise
print(s[0::2])       #Srrs
print(s+s2)          #SurpriseMotherFucker
print(s*2)           #SurpriseSurprise
print(len(s))        #8
print(min(s))        #S
print(max(s))        #u
print("S" not in s)  #False
print("M" in s2)     #True
```

#### 2. string分割函數
```python=
s3 = "I Love U"
print(s3.split())    #['I', 'Love', 'U']

mails = ["abcn@yahoo.com.tw", "wooddn@hotmail.com", "kkzaa@gmail.com"]
print(mails[0].split("@")[1].split(".")[0]) #先用@分割，再用.分割
#"yahoo"
```

#### 3. string去首尾函數
```python=
str1 = "乂JoJo乂乂"
str2 = "  乂JoJo乂乂  "
print(str1.strip("乂"))  #"JoJo"
print(str2.strip())      #"乂JoJo乂乂"
a = "\tabc"
b = "abc\n\r"
print(a.strip())         #"abc"
print(b.strip())         #"abc"
```



#### 5. string 單引號＆雙引號應用
```python=
print("I'm Joseph")      #雙引號內單引號不用跳脫
print('I\'m Joseph')     #單引號內有單引號要跳脫
print('I said "Why"')    #單引號內雙引號不用跳脫
print("I said \"Why\"")  #雙引號內有雙引號要跳脫
```

### **list**
定義1：list為**有序**且**可修改**之元素集合(mutable)
定義2：允許多個重複元素
定義3：允許list內元素為不同type
Example: name_list = ['Joseph', 'Emma', 'Julia', 'Julian']
| list              | Joseph | Emma | Julia | Julian |
| ------------------|--------|------|-------|--------|
| Index from head   | 0      | 1    | 2     | 3      |
| Index from tail   | -4     | -3   | -2    | -1     |

#### 1. 常見字串函數
```python=
name_list = ["Joseph", "Emma", "Julia", "Julian"]
name_list.append("Judy")      #['Joseph', 'Emma', 'Julia', 'Julian', 'Judy']
name_list.remove("Judy")      #['Joseph', 'Emma', 'Julia', 'Julian']
name_list2 = name_list.copy() #['Joseph', 'Emma', 'Julia', 'Julian']
name_list.index("Emma")       #1 (位置1)
name_list.extend(name_list2)  #['Joseph', 'Emma', 'Julia', 'Julian', 'Joseph', 'Emma', 'Julia', 'Julian']
name_list.count("Julia")      #2 (出現兩次)
name_list2.insert(2, "Judy")  #['Joseph', 'Emma', 'Judy', 'Julia', 'Julian']
del name_list2[2]             #['Joseph', 'Emma', 'Julia', 'Julian']
name_list2.pop()              #['Joseph', 'Emma', 'Julia'] (最尾巴的去除)
print(name_list2.pop())       #Julia, name_list2 = ['Joseph', 'Emma']
name_list.reverse()           #['Julian', 'Julia', 'Emma', 'Joseph', 'Julian', 'Julia', 'Emma', 'Joseph']
name_list.sort()              #['Emma', 'Emma', 'Joseph', 'Joseph', 'Julia', 'Julia', 'Julian', 'Julian']

#replace不改寫list，此用法會回傳新的字串
list1 = ["Holy", "Shit"]
list1[1].replace("S", "s")    #shit
print(list1)                  #["Holy", "Shit"]

name_list.clear()             #[]
```

#### 2.list合併函數
```python=
list1 = ["S", "H", "I", "T"]
print("".join(list1))  #SHIT
print('-'.join(list1)) #S-H-I-T
```

#### 3.list值合併函數
```python=
#list中值加總
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(sum(list1))  #45

#list與list之間合併
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = list1 + list2 #[1, 2, 3, 4, 5, 6]

#list與list之間合併成dict
list_a = ["Joseph", "Emma", "Julia"]
list_b = [1, 2, 3]
dic1 = dict(zip(list_a, list_b)) #{'Joseph': 1, 'Emma': 2, 'Julia': 3}
```

### **tuple**
定義1：tuple為**有序**且**不可修改**之元素集合(immutable)
定義2：“**不**”允許多個重複元素
定義3：允許tuple內元素為不同type
Example: person1 = ("Joseph", 180, 75)
| tuple             | Joseph | 180 | 75 |
| ------------------|--------|-----|----|
| Index from head   | 0      | 1   | 2  |
| Index from tail   | -3     | -2  | -1 |

#### 1. 常見字串函數
```python=
person1 = ("Joseph", 180, 75)
person1 += ("Taipei", )  #利用逗號來使程市判別()內為tuple而非運算用
print(person1)           #("Joseph", 180, 75, "Taipei")
print(person1[0])        #Joseph
print(person1[:2])       #Joseph 180
print(len(person1))      #4

#person1[0]與person1[0:1]不同，一個是單一文字，一個是tuple型態
print(person1[0])                 #"Joseph"
print(person1[0:1])               #("Joseph",)
print(person1[0:1] + person1[2:]) #("Joseph", 75, 'Taipei')

# tuple刪除？ 不用，因為本身是短暫用
# 要用也可，可以繞彎達成
```

#### 2.list合併函數
```python=
t1 = ("S", "H", "I", "T")
print("".join(t1))  #"SHIT"
print('-'.join(t1)) #"S-H-I-T"
```

#### 3.sort()函數
```python=
#Sorted()輸出為list
t1 = ("S", "H", "I", "T")
print(sorted(t1)) #['H', 'I', 'S', 'T']
```

## 4. Hash Type (dict, set)
### **dict**
定義1：dictionary為無序且一堆**key** & **value**之元素集合
定義2：key不可重複

#### 1. 常見字串函數
```python=
person = {"Name":"Joseph", "Height":180, "Handsome":True}

#取值: print(name)
print("Name: ", person["Name"])  #Name: Joseph

#新增語法
person["Weight"] = 75
print(person) #{'Name': 'Joseph', 'Height': 180, 'Handsome': True, 'Weight': 75}

#更新內容
person["Weight"] = 72
print(person) #{'Name': 'Joseph', 'Height': 180, 'Handsome': True, 'Weight': 72}

#數值取出來做運算並且更新
person["Height"] = person["Height"] +3
print(person) #{'Name': 'Joseph', 'Height': 183, 'Handsome': True, 'Weight': 72}

#刪除
del person["Weight"]
print(person) #{'Name': 'Joseph', 'Height': 177, 'Handsome': True}

#len
print(len(person))  #3
```

#### 2. iter()函數
```python=
lis1 = {"A":11, "B":22, "C":33, "D":44, "E":55}
print(id(lis1)) 
# printing type  
print ("The list is of type:" + str(type(lis1))) 
  
# converting list using iter() 
lis1 = iter(lis1) 
print(id(lis1))  

# printing type  
print ("The iterator is of type:" + str(type(lis1))) 
  
# using next() to print iterator values 
print (next(lis1)) 
print (next(lis1)) 
print (next(lis1)) 
print (next(lis1)) 
print (next(lis1))
```
### **set**
定義1：set為無序且無索引(index)之元素集合
定義2：不可重複元素

#### 1. 常見字串函數
```python=
name_set = {"周", "林", "黃", "周"}
print(name_set)        #{'黃', '周', '林'}

# 會改變set內部指令:add, discard
name_set.add("王")     #{'黃', '周', '林', '王'}
name_set.discard("王") #{'黃', '周', '林'}

#聯集:兩個的聯集
name_set = name_set.union({"何", "周"}) 
print(name_set)       #{'周', '何', '黃', '林'}
```

## 5. String formatting

```python=
a = 100
b = 8.9
c = "hello"
d = 1+2j
print("{} {} {}".format(a, b, c)  #"100 8.9 hello"
print("{0} {1} {2}".format(a, b, c))  #"100 8.9 hello"
print("{2} {1} {0}".format(a, b, c))  #"hello 8.9 100"
print("{0}, {0.real}, {0.imag}".format(d))  #(1+2j), 1.0, 2.0
print("x, y = {x}, {y}".format(x="3", y="4"))  #x, y = 3, 4

#dict type
coord = {"w": "6", "h": "8"}
print("w, h = {w}, {h}".format(**coord))  #w, h = 6, 8

#tuple type
coord2 = (8, 9)
print("X: {0[0]}; Y: {0[1]}".format(coord2))  #X: 8; Y: 9

#調整位數
#hint: d=integer f=float s=string
print('{0:10d} {1:10f} {2:10s}'.format(a, b, c)) #設10個位數
print('{0:>10d} {1:>10f} {2:>10s}'.format(a, b, c)) #靠右
print('{0:<10d} {1:<10f} {2:<10s}'.format(a, b, c)) #靠左
print('{0:^10d} {1:^10f} {2:^10s}'.format(a, b, c)) #靠中間
#'       100   8.900000 hello     '
#'       100   8.900000      hello'
#'100        8.900000   hello     '
#'   100      8.900000    hello   '

#進位
#hint: int:十進位 bin:二進位 oct:八進位 hex:十六進位
print('int: {0:d}; bin: {0:b}; oct: {0:o}; hex: {0:x}'.format(99))
#'int: 99; bin: 1100011; oct: 143; hex: 63'
print('int: {0:#d}; bin: {0:#b}; oct: {0:#o}; hex: {0:#x}'.format(99))
#'int: 99; bin: 0b1100011; oct: 0o143; hex: 0x63'
print(':,'.format(1234567890))
#'1,234,567,890'

#小數點
e = 33
f = 19
print('percentage = {:.2%}'.format(b/a))  #小數點兩位
#'percentage = 57.58%'

#時間格式
import datetime
date1 = datetime.datetime(2020, 1, 1, 12, 34, 56)
print('{:%Y-%m-%d %H:%M:%S}'.format(date1))
#'2020-1-1 12:34:56'
```
[f-string](https://www.twblogs.net/a/5b822eca2b717737e032da80)
Better and faster than format
```python=
a = 100
b = 8.9
c = 'hello'
d = 1+2j
print(f"{a} {b} {c}")  #"100 8.9 hello"

#dict type
coord = {"w": "6", "h": "8"}
print(f"w, h = {coord['w']}, {coord['h']}")  #w, h = 6, 8

#tuple type
coord2 = (8, 9)
print(f"X: {coord2[0]}; Y: {coord2[1]}")  #X: 8; Y: 9

#調整位數
#hint: d=integer f=float s=string
print(f"{a:10d} {b:10f} {c:10s}") #設10個位數
print(f"{a:>10d} {b:>10f} {c:>10s}") #靠右
print(f"{a:<10d} {b:<10f} {c:<10s}") #靠左
print(f"{a:^10d} {b:^10f} {c:^10s}") #靠中間
#'       100   8.900000 hello     '
#'       100   8.900000      hello'
#'100        8.900000   hello     '
#'   100      8.900000    hello   '

#進位
#hint: int:十進位 bin:二進位 oct:八進位 hex:十六進位
print(f"int: {99:d}; bin: {99:b}; oct: {99:o}; hex: {99:x}")
#'int: 99; bin: 1100011; oct: 143; hex: 63'
print(f"int: {99:#d}; bin: {99:#b}; oct: {99:#o}; hex: {99:#x}")
#'int: 99; bin: 0b1100011; oct: 0o143; hex: 0x63'
print(f"{1234567890:,}")
#'1,234,567,890'

#小數點
e = 33
f = 19
print(f"percentage = {f/e:.2%}")  #小數點兩位
#'percentage = 57.58%'

#時間格式
from datetime import datetime as dt
date1 = dt(2020, 1, 1, 12, 34, 56)
print(f"{date1:%Y-%m-%d %H:%M:%S}")
#'2020-1-1 12:34:56'      
```
# :memo: Flow
## 1. 條件式 if/else/elif
定義1：True/False條件敘述，若條件式為True則執行縮排內程式區塊
定義2：執行順序為if==>elif==>elif...==>else

```python=
import random
answer = random.randint(1, 5)
guess = int(input("Guess: "))
if guess > answer:
    print('{} is bigger than answer'.format(guess))
elif guess < answer:
    print('{} is smaller than answer'.format(guess))
else:
    print('bingo! is ', answer)
```

### 巢狀式流程控制
```python=
import random
answer = random.randint(1, 5)
guess = int(input("Guess: "))
if guess >= 1 and guess <=5:
    if guess > answer:
        print('{} is bigger than answer'.format(guess))
    elif guess < answer:
        print('{} is smaller than answer'.format(guess))
    else:
        print('bingo! is ', answer)
else:
    print("Guess is not in range")
```

## 2. 迴圈 while/for
### **while**
定義：在條件式為True時，可重複執行某一段程式區塊

```python=
answer = 3
guess = 0

while guess != answer:
    guess = int(input('please make guess during 1~6.: '))
    if guess > answer:
        print('bigger than answer')
        continue                    #直接跳去while那一行
    elif guess < answer:
        print('smaller than answer')
    else:
        print('bingo')
        break                       #中斷此while迴圈
    print('Still in while loop.\n')
```
### **for**
定義：用來迭代序列化資料，ex: list, tuple, dictionary
```python=
for i in 'Joseph':
    print(f'{i}', end='')  #f'{}'方便做帶入
#Joseph
```
```python=
Name_list = ['Joseph', 'Emma', 'Julian']
for i in Name_list:
    print(f'Name: {i}')
# Name: Joseph
# Name: Emma
# Name: Julian
for i in range(len(Name_list)):
    print(i)
    print(my_list[i])
# 0 Joseph
# 1 Emma
# 2 Julian
for index, i in enumerate(Name_list):
    print(index,i)
# 0 Joseph
# 1 Emma
# 2 Julian

pos = [i for i,x in enumerate(Name_list) if x == "Joseph"]
#[0]
```
```python=
for i in range(5):
    print(i, end='') #01234
print('')
for i in range(1, 5):
    print(i , end='') #1234
print('\n', end='')
for i in range(1, 10, 2):
    print(i, end='') #13579
print('\n', end='')
for i in range(5, 0, -1):
    print(i, end='') #54321
```
```python=
my_dict = {'Joseph':50, 'Emma':80, 'Judy':20}
for i in my_dict:
    print(i, my_dict[i])
# Joseph 50
# Emma 80
# Judy 20
for i in my_dict.values():
    print(i)
# 50
# 80
# 20
```
巢狀迴圈
```python=
n=5
for i in range(n):
    for j in range(i):
        print ('* ', end="")
    print('')

for i in range(n,0,-1):
    for j in range(i):
        print('* ', end="")
    print('')
# * 
# * * 
# * * * 
# * * * * 
# * * * * * 
# * * * * 
# * * * 
# * * 
# * 
```

# :memo: Function
## 自訂函數
定義：A-Z, a-z, *_*,0-9，第一個不能為數字
定義：可設計成輸入參數(parameters)與回傳值(return)
```python=
#可以設預設值
def score(name, grade, class1='Sunny'):
    print(name + "'s math grade is: %s" %grade)
    print(r'class is', class1)
score('Joseph', 98)
# Joseph's math grade is: 98
# class is Sunny

#可以將參數變“動參數”增加多個參數輸入
def namelist(*names):
    for name in names:
        print(name)
    return names  #--> tuple
namelist('Joseph', 'Emma', 'Julian')
# Joseph
# Emma
# Julian

#可以將參數變“動參數”接收字典
def feature(**keyvalue):
    print('FEATURE:', keyvalue)
    return keyvalue #-->dict
feature(Name='Joseph', Height=180, Handsome=True)
# FEATURE: {'Name': 'Joseph', 'Height': 180, 'Handsome': True}

#回傳值功能
def Returnfuc():
    a = 'apple'
    b = 'banana'
    c = 'cat'
    return a, b, c
print(Returnfuc())
# ('apple', 'banana', 'cat') type==>tuple
```
## 內建函數
![](https://i.imgur.com/Zd9ZCZR.png)
### 常用函數
```python=
abs(-1)     #1
round(3.4)  #3
pow(3,2)    #9
divmod(3,2) #(2,1)

str(10) #10
bin(10) #0b1010
oct(10) #0o12
hex(10) #0xa

list1 = [1,2,3,4,5]
sum(list1) #15
min(list1) #1
max(list1) #5

txt1='100'
a = int(txt1)
print(f'a = {a}, {type(a)}') #a = 100, <class 'int'>

txt2='100.87'
b = float(txt2)
print(f'b = {b}, {type(b)}') # b= 100.87, <class 'float'>
```

## 全域變數
定義：任何區塊的程式碼可存取之變數
```python=
def function2():
    global a #將變數a變為全域變數，函數跳出時變數a才不會消失
    a += 1   #變數a變成1000
    print(a)

a = 999
function2()
#1000
```

## 區域變數
定義：只能在程式區塊可存取之變數
```python=
def sumofbitch(a, b):
    c = a + b #變數a, b, c只存取於此程式區塊
    print(a)
    return c
print(sumofbitch(1,2))
#1 先運算sumofbitch(1,2)
#3 後print
```

## lambda函數
定義：使用一行就能完成函數定義
```python=
#before
def double(a):
    return a*2
double(5) #10

#after
x = lambda a:a*2
x(5)      #10
```

結合filter()可選則符合條件之元素
```python=
#filter(function, iterable)
list1 = [1,2,3,4,5,6,7,8,9]
odd_list = list(filter(lambda x:(x%2==1),list1))
print(odd_list)
# [1, 3, 5, 7, 9]
```

結合map()可選所有元素一起轉換
```python=
#map(function, iterable)
list1 = [1,2,3,4,5,6,7,8,9]
odd_list = list(map(lambda x:x**2,list1))
print(odd_list)
# [1, 4, 9, 16, 25, 36, 49, 64, 81]
```

結合reduce()可選多個元素做合併
```python=
#reduce(function, iterable)
from functools import reduce
list1 = [1,2,3,4,5]
odd_list = reduce(lambda x, y:x+y,list1)
print(odd_list) #((((1+2)+3)+4)+5)
# 15
```

## 遞迴函數
定義：自己呼叫自己
```python=
def factorial(n):
    if n==0 or n==1:
        return 1
    else:
        return n*factorial(n-1)

print(factorial(4)) #24
```
### 動態規劃
因為避免遞迴浪費太多記憶體，可先將部分函數存起來，要用到可直接取得
以費氏定理來舉例：
|F(0)|F(1)|F(2)|F(3)|F(4)|F(5)|F(6)|F(7)|F(8)|
|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
|0   |1   |1   |2   |3   |5   |8   |13  |21  |
```python=
#before
def F(n):
    if n==0 or n==1:
        return n
    else:
        return F(n-1)+F(n-2)
print(F(8))            #21

#after
def fibonacciVal(n):
    memo = [None]*(n+1)
    memo[0], memo[1] = 0, 1
    for i in range(2, n+1):
        memo[i] = memo[i-1]+memo[i-2]
    return memo[n]     #memo[2] = 1, memo[3] = 2,...
print(fibonacciVal(8)) #21
```

# :memo: Class
## 物件導向語言(Object-oritented Programming,OOP)
定義1：所有資料皆是物件
定義2：提高軟體重複使用性、方便擴充性、方便維護性

## 基本語法
定義：第一個字母要大寫
```python=
class Banks():
    title = 'Taiwan Bank'   
    def word(self):
        print("Hello!!")

bank1 = Banks()
print(bank1.title)
bank1.word() #有self需要有()
#Taiwan Bank
#Hello!!
```

### 1.\_\_init\_\_函數
class被創建時，\_\_init\_\_會被直接執行
```python=
class Banks(): 
    def __init__(self, uname):
        self.name = uname  #public==>他人可以查詢得到
        self.balance = 0
        self.bankname = "Taipei Bank"

    def save_money(self, money):
        self.balance += money
        print("save ", money, "Finish")

    def withdraw_money(self, money):
        self.balance -= money
        print("draw ", money, "Finish")

    def get_balance(self):
        print(self.name, "Rest: ", self.balance)

bank1 = Banks('Joseph')
bank1.save_money(300)     #save 300 Finish
bank1.get_balance()       #Joseph Rest:  300
bank1.withdraw_money(300) #draw  300 Finish
bank1.get_balance()       #Joseph Rest:  0
```

### 2.實體屬性(Instance Attribute)
定義：各自物件實體屬性各自獨立，修改某一物件屬性時，不會影響另一物件之屬性
```python=
class Banks(): 
    def __init__(self, uname):
        self.name = uname  #public==>他人可以查詢得到
        self.balance = 0
        self.bankname = "Taipei Bank"

    def save_money(self, money):
        self.balance += money
        print("save ", money, "Finish")

    def withdraw_money(self, money):
        self.balance -= money
        print("draw ", money, "Finish")

    def get_balance(self):
        print(self.name, "Rest: ", self.balance)

bank1 = Banks('Joseph')
bank2 = Banks('Emma')
bank1.save_money(300)     #save 300 Finish
bank1.get_balance()       #Joseph Rest:  300
bank2.save_money(1000)    #save 1000 Finish
bank2.get_balance()       #Emma Rest:  300
```

### 3.類別屬性(Class Attribute)
定義：各自物件共享類別屬性，類別屬性修改，各自物件之屬性一起修改
```python=
class Banks():
    location = "Taiwan"
    def __init__(self, uname):
        self.name = uname  #public==>他人可以查詢得到
        self.balance = 0
        self.bankname = "Taipei Bank"

    def save_money(self, money):
        self.balance += money
        print("save ", money, "Finish")

    def withdraw_money(self, money):
        self.balance -= money
        print("draw ", money, "Finish")

    def get_balance(self):
        print(self.name, "Rest: ", self.balance)

bank1 = Banks('Joseph')
bank2 = Banks('Emma')
print("original location:", bank1.location) #Taiwan
print("original location:", bank2.location) #Taiwan
Banks.location = "America"
print("New location:", bank1.location)      #America
print("New location:", bank2.location)      #America
```

### 4.屬性(Property)
定義：可控制類別中的屬性，並且可以用方法(method)來設定規則

```python=
#範例需求：Bank名字可以修改，但是要為字串
class Banks():
    location = "Taiwan"
    def __init__(self, uname):
        self.name = uname  #此處還是為public，後方則為private
        self.__balance = 0
        self.__bankname = "Taipei Bank"

    @property
    def name(self):
        # print('get name')
        return self.__name
    
    @name.setter
    def name(self, new_name):
        # print('set name')
        if type(new_name) == str:
            self.__name = new_name
        else:
            raise TypeError('name need str.')

    def save_money(self, money):
        self.__balance += money
        print("save ", money, "Finish")

    def withdraw_money(self, money):
        self.__balance -= money
        print("draw ", money, "Finish")

    def get_balance(self):
        print(self.__name, "Rest: ", self.__balance)
bank1 = Banks('JOJO')
print(bank1.name)   #JOJO
bank1.name = 'Emma'
print(bank1.name)   #名字修改成Emma
```

## 封裝(encapsulation)
將類別內attribute/method私有化，class外部無法使用內部資訊
使用方法：在attrubute/method前面加上"__"
```python=
#函數私有化==>__XXX
class Banks():   
    def __init__(self, uname):
        self.__name = uname #private==>私有化內容
        self.__balance = 0
        self.__bankname = "Taipei Bank"

    def save_money(self, money):
        self.__balance += money
        print("save ", money, "Finish")

    def withdraw_money(self, money):
        self.__balance -= money
        print("draw ", money, "Finish")

    def get_balance(self):
        print(self.__name, "Rest: ", self.__balance)

bank1 = Banks('Joseph')
bank1.save_money(300)     #save 300 Finish
bank1.__name = 'JoJo'     #經過封裝後修改無效化
bank1.get_balance()       #Joseph Rest:  300
bank1.withdraw_money(300) #draw  300 Finish
bank1.get_balance()       #Joseph Rest:  0
```

## 繼承(inheritance)
attribute/method可以被繼承
繼承者：子類別(subclass)
被繼承者：父類別(superclass)
```python=
class Banks(): 
    def __init__(self, uname, money):
        self.name = uname  #public==>他人可以查詢得到
        self.balance = money
        self.bankname = "Taipei Bank"

    def get_balance(self):
        print(self.name, "has: ", self.balance)
        return self.balance

class Daan_Banks(Banks):  #Daan_Banks == subclass
    pass                  #Banks == superclass
bank1 = Banks('Joseph', 1000)
bank1.get_balance()       #Joseph has:  1000
```

### 多重繼承
```python=
class Grandfather():
    def action1(self):
        print("I'm grandfather.")
class Father(Grandfather):
    def action2(self):
        print("I'm father.")
        super().__init__()
class Uncle(Grandfather):
    def action3(self):
        print("I'm uncle.")
        super().__init__()
class Son(Father, Uncle):
    def action4(self):
        print("I'm son.")
        super().__init__()

son = Son()
son.action1() #I'm grandfather.
son.action2() #I'm father.
son.action3() #I'm uncle.
son.action4() #I'm son.
```

## 多型(polymorphism)
預設狀態子類別會繼承父類別，但若子類別method與父類別相同，會覆寫父類別method
```python=
class Animals():
    def __init__(self, animal_name):
        self.name = animal_name
    def which(self):
        return 'Name:'+ self.name.title()
    def action(self):
        return 'sleeping'

#有繼承
class Dogs(Animals):
    def __init__(self, dog_name):
        super().__init__(dog_name.title())
    def which(self):
        return 'Name:'+ self.name.title()
    def action(self):
        return 'eating'

#無繼承
class Cats():
    def __init__(self, cat_name):
        self.name = 'Name:' + cat_name.title()
    def which(self):
        return self.name
    def action(self):
        return 'playing'
        
def do(obj):
    print(obj.which(), '', obj.action()) 

bear = Animals('JOJO')
do(bear) #Name:Jojo  sleeping
dog = Dogs('DOGGY')
do(dog) #Name:Doggy  eating
cat = Cats('Catty')
do(cat) #Name:Catty  playing
```

# :memo: try/except
使用時機：當執行程式時，可能會產生預期之外之行為，可使用try/except語法解決
```python=
#使用前
def divison(a, b):
    return a / b
print(divison(3,0)) 
#ZeroDivisionError: division by zero

#使用後
def divison(a, b):
    try:
        return a / b     # None
    except (ZeroDivisionError) as e:
        print('[Error]: Divisor can not be zero.')
        print(e)

print(divison(3,0))
# [Error]: Divisor can not be zero.
# division by zero
# None
```
## Raise語法
用Raise顯示Exception
```python=
def chkPWD(pwd):
    pwdlen = len(pwd)
    if pwdlen > 6:
        raise Exception('password is too long.')
    if pwdlen < 4:
        raise Exception('password is too short.')
    else:
        print('password correct!')

for pwd in ('abcdefg', 'abc', 'abcd'):
    try:
        chkPWD(pwd)
    except Exception as err_msg:
        print('Error occurs during password checking: ', str(err_msg))
# 所有皆有執行
# Error occurs during password checking:  password is too long.
# Error occurs during password checking:  password is too short.
# password correct!
```
## Assert語法
Assert可以幫助檢查變數是否符合期望，若不符合則產生例外
```python=
def chkPWD(pwd):
    pwdlen = len(pwd)
    assert pwdlen > 6, 'password is too long.'
    assert pwdlen < 4, 'password is too short.'
    print('password correct!')
    
print(chkPWD('abc'))
# 產生執行錯誤
# AssertionError: password is too long.
```

# :memo: 檔案處理(讀入、寫入)
## txt, csv檔案
CSV檔案為常見的資料儲存格式
定義：row之間用換行來區分，column用" ,"來區分
![](https://i.imgur.com/QWdjW4L.png =300x)

### open()
1.讀檔
[Documentation: open()](https://docs.python.org/3/library/functions.html#open)
```python=
#open後一定要close
path = "stock.csv"
f = open(path, "r", encoding = "UTF-8")
print(f.name)   #stock.csv
print(f.closed) #False
print(f.mode)   #r
f.close()
print(f.closed) #True
```
```python=
#with as用法可以省略
with open('stock.csv', 'r', encoding="UTF-8") as f:
    data1 = f.read()
print(data1)
# Code,Name,Close Price,Change Percent,Today Amount,Last Day Amount,Last 2Day Amount
# 2303,聯電,52.7,1.35,3967.0,5606.0,-2319.0
# 3545,敦泰,270.5,9.96,3012.0,962.0,227.0
# 2454,聯發科,933.0,1.52,1740.0,1547.0,-599.0
# 2603,長榮,154.0,7.32,1510.0,240.0,-9557.0
# 2338,光罩,101.5,6.06,1272.0,-624.0,907.0
# 2609,陽明,145.5,3.56,1260.0,-1026.0,-2362.0
# 2002,中鋼,36.3,3.12,1143.0,595.0,-970.0
# 1101,台泥,53.0,1.73,725.0,-216.0,138.0
# 2409,友達,20.7,5.08,708.0,-419.0,195.0
# 8261,富鼎,124.5,6.87,519.0,-19.0,-18.0
```
```python=
#readlines()  每一行列成list
with open('test1.txt', 'r', encoding="UTF-8") as f:
    data1 = f.readlines()
print(data1)
#['Python is powerful and fast;\n', 'plays well with other;\n', 'is open.']
```
2.寫檔
```python=
path = "test1.txt"
f = open(path, "w", encoding = "UTF-8")

txt = '''Python is powerful and fast;
plays well with other;
is open.'''

f.write(txt)
f.close()
# Python is powerful and fast;
# plays well with other;
# is open.
```
```python=
#with as用法可以省略
txt = '''Python is powerful and fast;
plays well with other;
is open.'''
with open('test1.txt', 'w', encoding="UTF-8") as f:
    data1 = f.write(txt)
# Python is powerful and fast;
# plays well with other;
# is open.
```

### Excel

# :memo: Internal Module
## 1. re module (Pattern正規化)
用法：用來抓取符合規定規則之字串
![](https://i.imgur.com/7DFuJKa.png)
![](https://i.imgur.com/AKqmHdz.png =720x380)

### **re.match()**
比對從第一字元開始是否與pattern相符(只要有一個地方錯就None)
```python=
import re
txt = 'hello, hey, hi, Salaheyo'
x = re.match('\w*', txt) # \w == [a-z, A-Z, 0-9], * == 任意個數之character
print(x)  #<re.Match object; span=(0, 5), match='hello'>
x = re.match('\w{5}, \w{2}', txt)
print(x)  #<re.Match object; span=(0, 9), match='hello, he'>
```
```python=
import re
phonenumber = "02-222-1234, 03-333-1234"
regex = "(\w{2})-\w{3}-\w{4}"
x = re.match(regex, phonenumber)

if x:
    print(x)  #<re.Match object; span=(0, 11), match='02-222-1234'>
    print("Valid phone number")
else:
    print("Invalid phone number")
#Valid phone number
```
```python=
import re
phonenumber = "(02)-222-1234, 03-333-1234"
regex = "(\w{2})-\w{3}-\w{4}"
x = re.match(regex, phonenumber)

if x:
    print(x)  #<re.Match object; span=(0, 11), match='02-222-1234'>
    print("Valid phone number")
else:
    print("Invalid phone number")
#Invalid phone number
```
如果要完整比對需要在結尾加$
```python=
import re
list1 = ['AB1234', 'A01234', '0A1234', '1234AB', '1234A0', '123401', '0A1234', 'BMW2299', 'ABC123', 'AB123']
regex = r'\d{4}\w{2}$|\w{2}\d{4}$|[A-Z]{3}\d{4}$' # 防止跳脫字元
for i in range(len(list1)):
    if re.match(cl_pattern, list1[i]):
        print("normal: ", list1[i])
    else:
        print("Fail: ", i)
```
### **re.search()**
搜尋任何有符合pattern的字串
```python=
import re
txt = 'Surprise mother fucker'
x = re.search(f'mother', txt)  #f'XXX'表示''為字串
print(x)
print(type(x))
```
```python=
import re
phonenumber = "(02)-222-1234, 03-333-1234"
regex = "\w{2}-\w{3}-\w{4}"
x = re.search(regex, phonenumber)

if x:
    print(x)  #<re.Match object; span=(15, 26), match='03-333-1234'>
    print("Valid phone number")
else:
    print("Invalid phone number")
#Valid phone number
```

### **re.findall()**
搜尋任何所有滿足pattern的字串
```python=
import re
txt = 'hello! 23 hi 111. how are 889.'
pattern = '\d+'  #\d == [0-9], + ==至少一個
x = re.findall(pattern, txt)
print(x)         #['23', '111', '889'] type=<list>
```
```python=
import re
phonenumber = "02-222-1234, 03-333-1234"
regex = r"\d{2}-\d{3}-\d{4}"  #r"xxx"，方便解除內部跳脫字元
x = re.findall(regex, phonenumber)

if x:
    print(x)
    print("Valid phone number")
else:
    print("Invalid phone number")
#['02-222-1234', '03-333-1234']
#Valid phone number
```
```python=
import re
ntu_id = "R05543049, B12345678, C87654321"
regex = r"(\w{1}[0|1]\d{7})"  #[1|2]表示有1 or 2
obj = re.findall(regex, ntu_id)

if obj:
    print(obj)
    print("Vaild id number")
else:
    print("Invaild id number")
#['R05543049', 'B12345678']
##Vaild id number
```
## 2. collections
[collections - 容器資料型態](https://docs.python.org/zh-tw/3/library/collections.html)
