---
# System prepended metadata

title: Python
tags: [Python, 基礎]

---

###### Tags: `Python` `基礎`

# Python
## 基本數據類型
### 整數

|   前綴   |    例子    | 進制 |
|:--------:|:----------:|:----:|
|    無    |   a = 10   |  10  |
| 0b or 0B | b = ob1010 |  2   |
| 0o or 0O |  c = 0o12  |  8   |
| 0x or 0X |  d = 0xa   |  16  |

```python=
>>> a = 10
>>> type(a)
<class 'int'>
>>> b = 0b1010
>>> b
10
>>> c = 0o12
>>> c
10
>>> d = 0xa
>>> d
10
```

### 浮點數
```python=
a = 1.2
b = .4
c = 1.2e-4 # 1.2乘於10的-4次方
```
```python=
>>> a = 1.2
>>> type(a)
<class 'float'>
>>> b = .4
>>> b
0.4
>>> c = 1.2e-4
>>> c
0.00012
```
#### 浮點數運算特例
##### // 取無條件捨去整數除法
```python=
>>> 2/4
0.5
>>> 2//4
0
```
##### 浮點數運算 結果還是浮點數
```python=
>>> 0.2 * 5
1.0
>>> 0.2 // 0.4
0.0
```

### 字串
可使用'''包起字串，中間就可以使用"與'
```python=
>>> a = '''test "1" '2' '''
>>> a
'test "1" \'2\' '

>>> print(a)
test "1" '2'
```
用\\包引號可以顯示引號
```python=
>>> a = "這是"家""
  File "<stdin>", line 1
    a = "這是"家""
            ^
SyntaxError: invalid syntax

>>> a = "這是\"家\""
>>> a
'這是"家"'
```

#### 字串操作
```python=
>>> a= "test"
>>> a[-2]
's'

>>> len(a)
4

>>> a = "1"
>>> b = "2"
>>> a + b
'12'

>>> a * b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'str'
>>> a * 10
'1111111111'
```

#### 字串格式化
##### 推薦用 f"" 
```python=
name = 'Python'
age = 27

new_str = "我是" + name + "," + "今年" + str(age) + "歲了"
print(new_str)

new_str_1 = "我是%s,今年%d歲了" % (name, age)
print(new_str_1)

new_str_2 = "我是{},今年{}歲了".format(name, age) #順序對應
print(new_str_2)

new_str_2b = "我是{name},今年{age}歲了".format(		#key value 對應
    name = 'aaa',
    age = 'bbb'
)
print(new_str_2b)

new_str_3 = f"我是{name},今年{age}歲了"
print(new_str_3)
```
##### 小數點精確度:.2f
:代表顯示幾位數
```python=
print(f"{age:.2f}")    # 27.00
```
##### 顯示正號:+
```python=
print(f"{age:+.2f}")    # +27.00
```

##### 對齊
```python=
num1 = 12
num2 = -23
num3 = 100
# 限制長度10預設靠右對齊
print(f"數字1是 {num1:10.2f}")        # 數字1是      12.00
print(f"數字2是 {num2:10.2f}")        # 數字2是     -23.00
print(f"數字3是 {num3:10.2f}")        # 數字3是     100.00
# 靠左對齊
print(f"數字1是 {num1:<10.2f}")       # 數字1是 12.00
print(f"數字2是 {num2:<10.2f}")       # 數字2是 -23.00
print(f"數字3是 {num3:<10.2f}")       # 數字3是 100.00
# 置中對齊
print(f"數字1是 {num1:^10.2f}")       # 數字1是   12.00   
print(f"數字2是 {num2:^10.2f}")       # 數字2是   -23.00  
print(f"數字3是 {num3:^10.2f}")       # 數字3是   100.00  
```    

### 布林值
```python=
>>> a = True
>>> type(a)
<class 'bool'>
```
### 空值
```python=
>>> a = None
>>> a
>>> type(a)
<class 'NoneType'>
```

## 列表
```python=
a = [1,2,3]
b = [1, 'abc', 2.0, ['a', 'b', 'c']]

print(a)
print(b)

print(a[0],a[1])	#預設會以空格間隔並換行
print(a[0],a[1], sep='-',end='**')	#修改間隔與結尾

c = b[1:3]		#從第幾個
print(c, type(c))	#['abc', 2.0] <class 'list'>
```
### 列表基本操作

```python=
list1 = [9, 1, -4, 3, 7, 11, 3]
print('list1的長度=',len(list1))
print('list1裡的最大值=',max(list1))
print('list1裡的最小值=',min(list1))
print('list1裡 3 這個元素一共出現{}次'.format(list1.count(3)))
```

```python=
list2 = ['a', 'c', 'd']
list2.append('e')	
print('list2=', list2)	# list2= ['a', 'c', 'd', 'e']
list2.insert(1,'b')
print('list2=', list2) 	# list2= ['a', 'b', 'c', 'd', 'e']list2.remove('b')
list2.remove('b')
print('list2=', list2)	# list2= ['a', 'c', 'd', 'e']
list2[0] = '1'
print('list2=', list2) 	# list2= ['1', 'c', 'd', 'e']
```

```python=
a = '123'
a[0] = 'a'	# TypeError: 'str' object does not support item assignment
```

### 列表翻轉
```python=
list3 = [1, 2, 3]
list3.reverse()
print('list3=', list3)	# list3= [3, 2, 1]
```

### 列表排序
```python=
list3 = [1, 2, 3]
list3.reverse()
print('list3=', list3)	# list3= [3, 2, 1]

list4 = [9, 1, -4, 3, 7, 11, 3]
list4.sort()
print('list4=', list4)	# list4= [-4, 1, 3, 3, 7, 9, 11]
list4.sort(reverse=True)
print('list4=', list4)	# list4= [11, 9, 7, 3, 3, 1, -4]
```

## 元組(Tuple)
```python=
a = (1, 2, 3)
b = 1,
print(a, type(a))	# (1, 2, 3) <class 'tuple'>
print(b, type(b)) 	# (1,) <class 'tuple'>

a = (1, 2, 3)
b = [1, 2, 3]
print(a[1])		# 2
print(a[1:3])		# (2, 3)
print(a[1:])		# (2, 3)
```

### 元組基本操作
元組內的值不可更動
```python=
tuple1 = (9, 1, -4, 3, 7, 11, 3)
print('tuple1的長度=',len(tuple1))		# tuple1的長度= 7
print('tuple1裡的最大值=',max(tuple1))		# tuple1裡的最大值= 11
print('tuple1裡的最小值=',min(tuple1))		# tuple1裡的最小值= -4
print('tuple1裡 3 這個元素一共出現{}次'.format(tuple1.count(3)))	# tuple1裡 3 這個元素一共出現2次
```

```python=
tuple2 = ('a', 'c', 'd')
tuple2[1] = 2 	# 元組不可賦值 翻轉、排序都不行
```

```python=
print(tuple1.index(9))	# 0
```
#### 元組進階操作
##### 切片
```python=
my_tuple = ('python', 3, 7, 3 )
print(my_tuple[0:2])		# ('python', 3)
```
##### 序列解包
```python=
my_tuple = ('python', 3, 7, 3 )
name, _, y, z = my_tuple	# 略過用下底線
print(name, y, z)		# python 7 3
```
```python=
my_tuple = ('python', 3, 7, 3 )
name, *_, = my_tuple		# 之後都略過
print(name)			# python
```
```python=
my_tuple = ('python', 3, 7, 3 )
name, *version, = my_tuple	# 之後的組成列表
print(name, version)		# python [3, 7, 3]
```
## 列表 & 元組 比較


|     列表     |            元組            |
|:------------:|:--------------------------:|
| 固定一塊內存 | 兩塊內存 一塊數據 一塊擴展 |
|  比元組靈活  |     建立&讀取比陣列 快     |


## 字典
不可改變的數據類型
```python=
a = {
    1: 'a',
    2: 'b',
    '3': 'c'
}

print(type(a))		# <class 'dict'>

l1 = [1, 2, 3]
b = {
    l1: 1
}
# TypeError: unhashable type: 'list'

t1 = (1, 2, 3)
c = {
    t1: l1
}
print(c)	# {(1, 2, 3): [1, 2, 3]}

d = dict()
print(d)		# {}

e = dict(a=1, b=2, c='a')
print(e)	# {'a': 1, 'b': 2, 'c': 'a'}
print(e['a']) 	# 1

e['c'] = 3
e['d'] = 123
print(e)	{'a': 1, 'b': 2, 'c': 3, 'd': 123}
```

### 字典基本操作
```python=
d = {
    'Name' : 'Jack',
    'Age' : 9,
    'Grade' : 5
}

print(d['Name'])		# Jack
print(d.get('name'))		# none

```

#### 取得有哪些 key
```python=
print(d.keys())		# dict_keys(['Name', 'Age', 'Grade'])
```

#### 取得有哪些 value
```python=
print(d.values())		# dict_values(['Jack', 9, 5])
```

#### 以元組方式取得結果
```python=
print(d.items())		# dict_items([('Name', 'Jack'), ('Age', 9), ('Grade', 5)])
```

#### pop
```python=
c= d.pop('Name')
print(c)		# Jack
print(d)		# {'Age': 9, 'Grade': 5}
```

#### clear
```python=
d.clear()
print(d)		# {}
```

#### update
```python=
c = {
    1: 1,
    2: 2
}

d = {
    5: 5,
    6: 6
}

c.update(d)
# c |= d
print(c)		# {1: 1, 2: 2, 5: 5, 6: 6}

e = {**c, **d}
# e = c | d
print(e)		# {1: 1, 2: 2, 5: 5, 6: 6}
```


### 字典進階操作
#### dict().setdefault 算重複次數
```python=
word_list = ['is', 'who', 'when', 'it', 'is', 'who', 'is']

result = dict()

# for word in word_list:
#     if word not in result:
#         result[word] = 1
#     else:
#         result[word] += 1
#
# print(result)

for word in word_list:
    result.setdefault(word, 0)
    result[word] += 1

print(result)		# {'is': 3, 'who': 2, 'when': 1, 'it': 1}
```
#### 初始化字典
defaultdict(類型)
```python=
word_list = ['is', 'who', 'when', 'it', 'is', 'who', 'is']

from collections import defaultdict

result = defaultdict(int)
for word in word_list:
    result[word] += 1
    
print(result)		# defaultdict(<class 'int'>, {'is': 3, 'who': 2, 'when': 1, 'it': 1})
```
## 集合
```python=
a = { 'a', 'b', 'c' }

b = {
    'a': 1,
    'b': 2,
    'c': 3
}
print(type(a))		# <class 'set'>

t = 'c' in a
print(t)		# True

l = [1, 2, 3, 2, 4, 5, 2]
s1 = set(l)
print(s1)		# {1, 2, 3, 4, 5}
print(list(s1))		# [1, 2, 3, 4, 5]

a = '1234512'
s1 = set(a)
print(s1)		# {'4', '3', '5', '1', '2'}
```

### 集合基本操作
```python=
s = { 1, 2, 3, 4 }
s.add(5)	
print(s)		# {1, 2, 3, 4, 5}
s.remove(5)
print(s)		# {1, 2, 3, 4}

```

#### 集合交集
```python=
s1 = { 1, 2, 3, 4 }
s2 = { 3, 4, 5, 6 }
print(s1 & s2)		# {3, 4}
```

#### 集合全集
```python=
s1 = { 1, 2, 3, 4 }
s2 = { 3, 4, 5, 6 }
print(s1 | s2)		# {1, 2, 3, 4, 5, 6}
```

#### 集合差集
```python=
s1 = { 1, 2, 3, 4 }
s2 = { 3, 4, 5, 6 }
print(s1 ^ s2)		# {1, 2, 5, 6}
```

#### 集合相減
有存在的條件就去除
```python=
s1 = { 1, 2, 3, 4 }
s2 = { 3, 4, 5, 6 }
print(s1 - s2)		# {1, 2}
print(s2 - s1)		# {5, 6}
```

## 條件
### if
```python=
a = int(input('請輸入一個數字:'))	# 12
print(a,type(a))			# 12 <class 'int'>
if a > 0:
    print('這是一個大於0的數字')		# 這是一個大於0的數字
```
### if ... else
```python=
a = int(input('請輸入一個數字:'))	# 0
print(a,type(a))			# 0 <class 'int'>
if a > 0:
    print('這是一個大於0的數字')
else:
    print('這是一個小於或等於0的數字')	# 這是一個小於或等於0的數字
```

### if ... elif ... else
```python=
a = int(input('請輸入一個數字:')) 	# 0
print(a,type(a)) 			# 0 <class 'int'>
if a > 0:
    print('這是一個大於0的數字')
elif a == 0:
    print('這是0')			# 這是0
else:	
    print('這是一個小於0的數字')
```

## 循環
### while
```python=
a = 10
while a > 0:
    print(a)		# 10 9 8 7 6 5 4 3 2 1
    a -= 1
print('結束')		# 結束
```

### for
```python=
a = '12345'
b = [1, 2, 3, 4]
c = ('a','b','c','d')
d = {
    1: 'a',
    2: 'b',
    3: 'c'
}
for item in d:
    print(item)
# in a: 1 2 3 4 5
# in b: 1 2 3 4 
# in c: a b c d 
# in d: 1 2 3 
```
```python=
d = {
    1: 'a',
    2: 'b',
    3: 'c'
}
for item in d.items():
    print(item)
# (1, 'a')
# (2, 'b')
# (3, 'c')
for a, b in d.items():
    print('{}={}'.format(a,b))
# 1=a
# 2=b
# 3=c
```
```python=
e = {1, 2, 3, 4, 5}
for item in e:
    print(item)
# in d: 1 2 3 5 9
```

#### range(start,stop,step)
```python=
for item in range(1, 20, 4):
    print(item)
# 1 5 9 13 17
```

#### enumerate(list)
```python=
items = ['a','b','c','d']
for index,item in enumerate(items):
    print(index,item)
# 0 a
# 1 b
# 2 c
# 3 d
```

## break & continue
### break
```python=
for i in range(10):
    print(i)			# 0 1
    if i % 2 != 0:
        break
```
### continue
```python=
for i in range(10):
    if i % 2 == 0:
        continue
    print(i)		# 1 3 5 7 9
```
#### 練習
```python=
import random
answer = random.randint(0, 100)
guess = int(input('請猜0~100間的數字: '))
max = 100
min = 0
while guess != answer:
    if guess == answer:
        break
    elif guess > answer:
        max = guess
        guess = int(input(f'請猜{min}~{max}間的數字: '))
    else:
        min = guess
        guess = int(input(f'請猜{min}~{max}間的數字: '))
print('答對了，答案是:', guess)
```

## 函數
```python=
def demo():
    print('hello world')

demo()		# Hello World

def demo1(a, b):	
    print(a, b)

demo1(a=[1,2,3],b={1:1,2:2})		# [1, 2, 3] {1: 1, 2: 2}

def sum(a,b):
    return a + b

print(sum([1,2],[3,4]))		# [1, 2, 3, 4]
``` 
### 練習 e.x.最大值
```python=
def my_max(a):
    if not a:
        return None
    max_value = a[0]
    for item in a:
        if item > max_value:
            max_value = item
    return max_value

a = [1, 4, 5, 2, 3, 8, 10]
print(my_max(a))
``` 
## scope
```python=
x = 1
x += 1
print(x)		# 2

def demo():
    x = 10
		a = 11
    print(x)		# 10
		
print(a)		# NameError: name 'a' is not defined
demo()
print(x)		# 2
``` 
```python=
y = [1, 2, 3]
print(y)		# [1, 2, 3]

def demo1(a):
    a = a + [4]
    print(a)		# [1, 2, 3, 4]
    
demo1(a=y)
print(y)		# [1, 2, 3]
``` 
### 用append等函數會改變全域變數
```python=
y = [1, 2, 3]
print(y)		# [1, 2, 3]

def demo1(a):
    a.append(4)
    print(a)		# [1, 2, 3, 4]
    
demo1(a=y)
print(y)		# [1, 2, 3, 4]
``` 

### 函數更改全域變數的方式
```python=
z = 1
print(z)		# 1
def demo2(a):
    global z		# global
    z = z + a
    print(z)		# 11

demo2(10)
print(z)		# 11
``` 

## 可變參數
可變參數必須放最後面
### *args
```python=
def add(*args):		# *args接受多個參數成一個元組
    print(args)		# (1, 2 ,3)
    result = 0
    for item in args:
        result += item
    return result
print(add(1, 2, 3))		# 6
``` 
### **kwargs
```python=
def add(**kwargs):		#**kwargs接受多個參數成一個字典
    print(kwargs)		# {'a': 1, 'b': 2, 'c': 3}
		return (kwargs.get('a') + kwargs.get('b')) * kwargs.get('c')
print(add(a=1, b=2, c=3))		# 9
``` 

### 參數默認值
有默認值的參數要放在最後
```python=
def test(a,b=False):
    if b:
        return a
    else:
        return a * a
print(test(a=2,b=True))	# 2
``` 

## 遞歸
```python=
# n! = 1*2*3.........(n-1)*n
# n * (n-1) * (n-2)...... 2*1!
# def test(n):
#     result = 1
#     for item in range(1,n+1):
#         result *= item
#     return result

def test(n):
    if n==1:
        return n
    return n * test(n-1)
print(test(4))		# 24
``` 
## 推導式
用更少的語法創建新列表

### 列表推導式
* [運算 迴圈 條件式]

原寫法:
```python=
def square(x):
    return x * x

list=[]

for i in range(1 , 11):
    list.append(square(i))
print(list)
```
推導式寫法:
```python=
newSquare = [i*i for i in range(1 , 11)]
print(newSquare)
```


e.x:
```python=
grades = [100,98,84,77,66,45]
passed_grades = [i for i in grades if i>=60]
print(passed_grades)
```

### 字典推導式
* {key:expression for (key,value) in interable}

e.x:
```python=
cities_in_F = {'LA': 120, 'New York': 65, 'Chicago': 50, "Miami": 150 }
cities_in_C = { key: (value - 32) * 5 / 9 for (key, value) in cities_in_F.items() }

print(cities_in_F)
print(cities_in_C)
```

e.x:
```python=
weather = {'台北': '大晴天', '台中': '大晴天', '宜蘭': '下雨', '台東': '下雨' }
sunny_weather = {key: value for (key, value) in weather.items() if value == '大晴天'}

print(sunny_weather)
```

e.x:
```python=
cities_in_F = {'LA': 120, 'New York': 65, 'Chicago': 50, "Miami": 150 }

def check_temp(value):
    if value >= 70:
        return '熱'
    elif value >= 40:
        return '溫暖'
    else:
        return '冷'

description_cities = { key: check_temp(value) for (key,value) in cities_in_F.items()}

print(description_cities)
```

## zip函式
三個以上的物件就無法轉成列表跟字典
```python=
usernames = ["Raiden", "Rodes", "ZZ"]
passwords = ("123", "321", "666")

users = zip(usernames,passwords)
print(users)            
# <zip object at 0x000001A07749C700>
```
```python=
for i in users:
    print(i)
    
# ('Raiden', '123')
# ('Rodes', '321')
# ('ZZ', '666')
```
```python=
print(list(users))
# [('Raiden', '123'), ('Rodes', '321'), ('ZZ', '666')]
```
```python=
print(dict(users))
# {'Raiden': '123', 'Rodes': '321', 'ZZ': '666'}
```
```python=
usernames = ["Raiden", "Rodes", "ZZ"]
passwords = ("123", "321", "666")
date = ["2000-11-13","1989-11-13","2020-11-13"]
users = zip(usernames,passwords,date)
print(users)        
for i in users:
    print(i)
print(list(users))
print(dict(users))

# <zip object at 0x0000017E510FC900>
# ('Raiden', '123', '2000-11-13')
# ('Rodes', '321', '1989-11-13')
# ('ZZ', '666', '2020-11-13')
# []
# {}
```

## class & object
### class
```python=
# __init__() method 方法
# attribute 屬性
# method 方法
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def sayhi(self):
        print("Hi my name is {}, and I'm {}".format(
            self.name, self.age
        ))

someone = People(name='Jack', age=20)
print(someone.name)	# Jack
print(someone.age)	# 20
someone.sayhi() 	# Hi my name is Jack, and I'm 20
``` 
### 受保護屬性 & 私有屬性
_:只是標記受保護，可修改 __: 只有class內可修改
```python=
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self._protect_var = 10
        self.__private_var = 10
    def sayhi(self):
        print("Hi my name is {}, and I'm {}".format(
            self.name, self.age
        ))
				
    def get_var(self):
        print(self.__private_var)
    def set_var(self,var):
        self.__private_var = var

someone = People(name='Jack', age=20)
someone.sayhi()		# Hi my name is Jack, and I'm 20
someone.age = 30
someone.sayhi()		# Hi my name is Jack, and I'm 30
someone._protect_var = 30
print(someone._protect_var)	# 30
print(someone.__private_var)	# AttributeError: 'People' object has no attribute '__private_var'

someone.get_var()		# 10
someone.set_var(30)
someone.get_var()		# 30
``` 

```python=
someone._protect_var = 30
print(someone._People__private_var)	# 10
someone._People__private_var = 30
someone.get_var()			# 30
``` 

### property
```python=
class People:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def name(self):
        # 格式規範
        return self.__name.upper()

    @property
    def age(self):
        return self.__age

    @name.setter
    def name(self, name):
        # 合法性檢查
        self.__name = name

    def set_age(self, age):
        self.__age = age

someone = People(name='Jack', age=20)
print(someone.name)		# JACK
print(someone.age)		# 20
someone.name ='Test'	# TEST
print(someone.name)
``` 

## 繼承和多態
```python=
class Animal:
    def eat(self):
        print('Animal is eating')

class Bird(Animal):
    def sing(self):
        print('Bird is singing...')
    def eat(self):
        print('Bird is eating...')

class Cat(Animal):
    pass

class Dog(Animal):
    def eat(self):
        print('Dog is eating')


a = Animal()
b = Bird()
c = Cat()
d = Dog()

def demo_eat(a):
    a.eat()

for item in [a, b, c, d]:
    demo_eat(item)
		
# Animal is eating
# Bird is eating...
# Animal is eating
# Dog is eating
```

## 類屬性 & 實例屬性
```python=
class Student:
    count = 0				# 類屬性
    def __init__(self, name):
        self.name = name		# 實例屬性
print(Student.count)			# 0
```
```python=
class Student:
    count = 0				# 類屬性
    def __init__(self, name):
        self.name = name		# 實例屬性
				
s1 = Student(name='A')
print(s1.name)				# A
```
```python=
class Student:
    count = 0
    def __init__(self, name):
        Student.count +=1
        self.name = name

s1 = Student(name='A')
s2 = Student(name='B')
s3 = Student(name='C')

print(Student.count)		# 3
```

## 類方法 & 實例方法 & 靜態方法
```python=
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def sayhi(self):		# 實例方法
        print(f"Hi, my name is {self.name}, and I'm {self.age}")

    @classmethod		# 類方法
    def test1(cls):
        print('這是一個類方法')
		@staticmethod		# 靜態方法
    def test2():
        print('這是一個靜態方法')
				
p1 = People(name='Jack',age=20)
p1.sayhi()			# Hi, my name is Jack, and I'm 20
p1.test1()			# 這是一個類方法
People.test1()			# 這是一個類方法
p1.test2()			# 這是一個靜態方法
People.test2()			# 這是一個靜態方法
```

## Package
### 新增 Package
New -> Python Package
### 建立引用檔案
math.py
```python=
def my_sum(*args):
    result = 0
    for item in args:
        result += item
    return result

def my_max(*args):
    print('最大值')

def my_min(*args):
    print('最小值')

class People:
    def __index__(self, name, age):
        self.name = name
        self.age = age
```
### 引入檔案
test.py
```python=
from ch8.demo.math import my_sum
print(my_sum(1, 2, 3, 4))		# 10
```

```python=
import ch8.demo.math as myMath
print(myMath.my_sum(1, 2, 3, 4))		# 10
```

### sys
import sys 在終端機執行程式，路徑才不會報錯

## 異常處理
### try ... except
```python=
a = [10, 4, 3, 7, 11, 6, 0, 9, 22]

try:
    b = [item for item in a if 100% item == 0]
except:
    print('發生錯誤')
print('完成')
# 發生錯誤
# 完成
```
except 可接錯誤類型(只捕捉該類異常)
```python=
a = [10, 4, 3, 7, 11, 6, 0, 9, 22]

try:
    b = [item for item in a if 100% item == 0]
except ZeroDivisionError:
    print('O不能為除數')
print('完成')
# O不能為除數
# 完成
```
其餘異常
```python=
a = [10, 4, 3, 7, 11, 6, 1, 9, 22,'10']

try:
    b = [item for item in a if 100% item == 0]
except ZeroDivisionError:
    print('O不能為除數')
except TypeError:
    print('數據類型錯誤')
except Exception:
    print('其它類型異常')

print('完成')
```
finally無視異常照樣執行
```python=
a = [10, 4, 3, 7, 11, 6, 1, 9, 22,'10']

try:
    b = [item for item in a if 100% item == 0]
except ZeroDivisionError:
    print('O不能為除數')
except TypeError:
    print('數據類型錯誤')
except Exception:
    print('其它類型異常')
finally:
    print('清理工作')
```
### 自定義異常
raise
```python=
class MyException(Exception):
    pass

raise MyException("這是用戶定義異常")
# Traceback (most recent call last):
#   File "C:\Users\fixer2\PycharmProjects\Python3-OOP\ch11\user_defined_exception.py", line 4, in <module>
#     raise MyException("這是用戶定義異常")
# __main__.MyException: 這是用戶定義異常
```

```python=
class MyException(Exception):
    pass

try:
    raise MyException("這是用戶定義異常")
except MyException as e:
    print(e)		# 這是用戶定義異常
```

```python=
class MyException(Exception):
    pass

def my_interaction():
    raise MyException('這是用戶定義的異常')

try:
    my_interaction()
except MyException as error:
    print(error)
else:
    print('Executing the else clause.')

try:
    my_interaction()
except MyException as error:
    print(error)
else:
    try:
        with open('file.log') as file:
            read_data = file.read()
    except FileNotFoundError as fnf_error:
        print(fnf_error)
finally:
    print('清理工作')

# 這是用戶定義的異常
# 這是用戶定義的異常
# 清理工作
```

## 測試
### pdb
```python=
import pdb
pdb.set_trace()

numbers = [1, 2, 3, 4, 10, -4, -7, 0]

def all_even(num_list):
    even_numbers = []
    for number in num_list:
        if number%2 == 0:
            even_numbers.extend(number)
    return even_numbers

all_even(numbers)
```
```python
-> numbers = [1, 2, 3, 4, 10, -4, -7, 0]
(Pdb) 
```


|      |      s       |      n       |          p           |
| ---- |:------------:|:------------:|:--------------------:|
| 用法 | 一行一行執行 | 直接執行函數 | 接函數名稱可印出內容 |

### Pychram Debug

### doc test
```python
def func_demo(a,b):
    """
     doc test demo
    >>> func_demo(1, 2)
    3
    >>> func_demo('a', 'b')
    'ab'
    >>> func_demo([1, 2], [3, 4])
    [1, 2, 3, 4]
    >>> func_demo(1, '2')
    Traceback (most recent call last):
    TypeError: unsupported operand type(s) for +: 'int' and 'str'
    """
    return a + b

if __name__ == "__main__":
    import doctest
    doctest.testmod()
```

### 單元測試
```python=
import unittest
from demo.math import add

class TestAdd(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(1, 2), 3)

if __name__ == '__main__':
    unittest.main()
		

```
```python
Ran 1 test in 0.010s

OK
```
```python=
import unittest
from demo.math import add

class TestAdd(unittest.TestCase):
    def test_add(self):
        self.assertEqual(add(1, 2), 3)

    def test_add_2(self):
        self.assertEqual(add(10, 20), 300)

if __name__ == '__main__':
    unittest.main()
```
```python
Ran 2 tests in 0.021s

FAILED (failures=1)


300 != 30

Expected :30
Actual   :300
<Click to see difference>

Traceback (most recent call last):
  File "C:\Users\fixer2\PycharmProjects\Python3-OOP\ch12\test_math.py", line 9, in test_add_2
    self.assertEqual(add(10, 20), 300)
AssertionError: 30 != 300
```

## 日誌紀錄 logging
```python=
"""
debug(), info(), warning(), error(), critical() 越右邊級別越高
"""
import logging

logging.basicConfig(level='DEBUG') # 設定顯示哪個級別的log

logging.debug('this is debug')
logging.info('this is info')
logging.warning('this is warning')
logging.error('this is error')
logging.critical('this is critical')
```
```python
DEBUG:root:this is debug
INFO:root:this is info
WARNING:root:this is warning
ERROR:root:this is error
CRITICAL:root:this is critical
```
### filename & filemode
filename: 將log輸出成檔案
filemode: 預設為a增加寫入，w為覆蓋寫入
```python=
logging.basicConfig(level='DEBUG', filename='test.log', filemode='w')
```

### logging format 設置
```python=
import logging

format = '%(levelname)s-%(name)s-%(message)s'		# 格式設置

logging.basicConfig(level='INFO', format=format)

def main():
    logging.debug('this is debug')
    logging.info('this is info')
    logging.warning('this is warning')
    logging.error('this is error')
    logging.critical('this is critical')

if __name__ == "__main__":
    main()
```
```python
INFO-root-this is info
WARNING-root-this is warning
ERROR-root-this is error
CRITICAL-root-this is critical
```

### logging 對象設置
```python=
import logging

logger = logging.getLogger(name='demo')
logger.setLevel(logging.DEBUG)

# Create handlers
c_handler = logging.StreamHandler()
f_handler = logging.FileHandler('file.log')
c_handler.setLevel(logging.ERROR)
f_handler.setLevel(logging.INFO)

# Create formatters and add it to handlers
c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
c_handler.setFormatter(c_format)
f_handler.setFormatter(f_format)

# Add handlers to the logger
logger.addHandler(c_handler)
logger.addHandler(f_handler)

def main():
    logger.debug('this is debug')
    logger.info('this is info')
    logger.warning('this is warning')
    logger.error('this is error')
    logger.critical('this is critical')

if __name__ == "__main__":
    main()
```
```python
demo - ERROR - this is error
demo - CRITICAL - this is critical
```

### 使用配置文件設定 logger (log.conf))





## time模組

```python=
import time
print(time.ctime(0))
print(time.time())
local_time = time.localtime()
print("格式化時間:",time.strftime("%Y-%m-%d %H:%M:%S", local_time))

# Thu Jan  1 08:00:00 1970
# 1709954820.1143064
# 格式化時間: 2024-03-09 11:27:00
```

字串轉時間的物件
```python=
import time
time_string = "2024-03-09 11:30:30"
time_object = time.strptime(time_string,"%Y-%m-%d %H:%M:%S")

print(time_object)
# time.struct_time(tm_year=2024, tm_mon=3, tm_mday=9, tm_hour=11, tm_min=30, tm_sec=30, tm_wday=5, tm_yday=69, tm_isdst=-1)
```