---
title: Python Learning Note
tags: python
---
[TOC]
## Fundamental Concept
1. Python為一[強型別程式語言](https://stackoverflow.com/questions/11328920/is-python-strongly-typed)
![](https://i.imgur.com/b58Zw3U.png)
2. Python的語法中沒有`{}`,因此是用縮排(indent)來判別範圍,縮排並沒有規定為多少空格,只要統一即可
3. Python中所有的東西都是物件,變數實際上是參考到一個物件(可以用id查看)
- Immutable object:此物件的內容不能被更改,所以對此物件的更改實際上是創造一個新的物件,並將新物件的參考assign給變數
- 傳遞參數時**類似C/C++ call by value**
- 常見的有: int、str、tuple
- Mutable object:此物件內容可以被更改,因此每次對其做的更改,都對該物件的參考做更改
- 傳遞參數時**類似C/C++ call by reference**
- 常見的有: list、dict
- 這個觀念非常重要,一開始初學時因為不知道所以很常碰壁
4. 註解符號
- Single Comment: `#後面內容為單行註解`
- Mutiple Comment: `""" 內容為多行註解 """`
5. Keyword
1. `pass`
- 如同字面上的意思,當程式運行到 pass statement 時,會略過
- 非常常見,像是一開始規劃程式時,可以列出需要的function,但function body不能為空,此時就可以用pass略過;或是在處理Exception時,有時遇到一些例外可以略過不處理,也會用到pass
2. `is`
- 用來判斷兩物件是否相等,跟`==`不同的是,`is`比較是兩物件的記憶體位址,`==`比較的是兩物件的值
- 為什麼要有`is`和`==`,事實上跟第三點有關,如果看到這裡還無法明白且暫時不去思考,看完整篇筆記就會知道了
## Control Statement
### If Satement
```python=
if condition:
handle statement
elif condition:
handle statement
else:
handle statement
```
Condition 的部分可以加括號亦可不加
### Ternary Operator
:::danger
Python 沒有 Ternary Operator
:::
```python=
# 第一種方法
True Satement if Condition else False Satement
# 第二種方法
(True Satement, False Satement)[Condition]
# 歡迎提供更多方法
```
### Switch Statement
:::danger
Python 沒有 switch statement
:::
替代方案有蠻多種,這裡提供一個我自己用過還不錯的
```python=
# 使用 dict 模擬 switch
# 使用時機為 內容行為可以直接用function處理
# 為不影響篇幅,假設fun已存在
handler = {
'1' : fun1,
'2' : fun2,
'3' : fun3,
}
# 執行
fun_handle = handler[choice]
fun_handle()
# 簡化
handler[choice]()
# 更好的寫法
handler.get(choice, lambda:print('No option'))()
```
## Loop
### While Loop
```python=
# 注意縮排
while Condition:
statement
```
### For Loop
?? python的for好像是用到iterator、generator的概念,這個我還不是很清楚,先用例子記起來吧
```python=
# Increment
for i in range(5):
print(i, end=' ') # 0 1 2 3 4
for i in range(2, 5):
print(i, end=' ') # 2 3 4
for i in range(1, 5, 2):
print(i, end=' ') # 1 3
# Decrement
for i in range(5, 0, -1):
print(i, end=' ') # 5 4 3 2 1
# List & Tuple
listA = ['A', 'B', 'C']
for idx in range(len(listA)):
print(listA[idx]) # A B C
for elem in ['A', 2, 'C', 4]:
print(elem, end=' ') # A 2 C 4
for key, value in [(1, 'one'), (2, 'two')]:
print(f'{key}={value}', end= ' ') # 1=one 2=two
```
## Function
### Basic Function Prototype
```python=
def FunctionName(Parameter List):
Function Body
```
### Return None Type
這邊需要注意的是,function可以不回傳東西,因此若沒有明確指定要回傳甚麼,都是回傳 `None` 這個特殊型別
```python=
# 以下三種寫法回傳值皆為 None
def fun1():
print('Hello')
def fun2():
print('Hello')
return
def fun3():
print('Hello')
return None
```
### Multiple Return Values
Python 允許同時回傳多個回傳值,以**Tuple**形式回傳
```python=
def fun(a, b, c):
return a, a+b, a+b+c # 等同於 return (a, a+b, a+b+c)
n = fun(1,2,3) # n = (1,3,6)
n1, n2, n3 = fun(1,2,3) # n1=1, n2=3, n3=6
n1, n3 = fun(1,2,3) # Try and Test(T1)
```
### Parameter has Default Value
Python 允許有Default Value,規則是通用的一律從右邊開始省略
```python=
def fun(a, b=5, c=10):
return a+b+c
n1 = fun(1,2,3) # n1=6
n2 = fun(1,2) # n2=13
n3 = fun(1) # n3=16
```
### Position & Keyword Arguments
在Python傳遞參數時,除了用位置對齊以外,還可以用parameter的名字來指定
注意:**position argments 不能在 keyword arguments 的右邊**
```python=
def say(name, msg):
print(name, msg)
say('Tom', 'Hi') == say(msg='Hi', name='Tom') == say('Tom', msg='Hi')
```
### Advanced Function Prototype
> 你可以不會寫,但是遇到必須看得懂
```python=
def FunctionName(arg, *args, **kwargs):
Function Body
```
`*args`:允許傳入可變動position參數,儲存資料型態為 tuple
`**kwargs`:允許傳入可變動keyword參數,儲存資料型態為 dictionary
> 若要同時使用則 `*args` 需要在 `**kwargs` 的左邊
```python=
def fun(arg, *args, **kwargs):
print(f'arg = {arg}')
print(f'args = {args}')
print(f'kwargs = {kwargs}')
# 執行函數
fun(1, 2, 3, k1=4, k2=5)
# 觀察輸出結果
Output:
arg = 1 # Position Argument
args = (2, 3) # Mutable Position Argument, which type is Tuple
kwargs = {'k1': 4, 'k2': 5} # Mutable Keyword Argument, which type is dictionary
```
對於`*args、**kwargs`該如何運用?
你只需要記得他們的型別為何,就可以運用自如
```python=
# *args mutable position arguments
def fun(*args):
sum = 0
for num in args:
sum += num
print(f'sum is {sum}')
# Try & Test(T2)
# 這樣的寫法非常蠢,想想看有沒有更簡短的寫法
fun(1,2,3,4,5,6,7,8,9,10)
# 如果我只想加1~10的奇數就好,該怎麼寫
# (我用到List Comprehension,還沒看到可以跳過)
Output:
sum is 55
```
```python=
# **kwargs mutable keyword arguments
def fun(**kwargs):
for key, value in kwargs.items():
print(f'({key}, {value})')
fun(k1='one', k2='two', k3='six')
Output:
(k1, one)
(k2, two)
(k6, six)
```
傳遞參數時可以使用`*args、**kwargs`
```python=
def fun(a1, a2, a3):
print(f'a1={a1}, a2={a2}, a3={a3}')
# 設定變數
nums = (1,2,3) # Try & Test 將Tuple改成List(T3)
kwnums = {'a3' : 6, 'a1' : 4, 'a2' : 5}
# 傳遞給函式,這樣的寫法有一種將它展開的感覺
fun(*nums)
fun(**kwnums)
Output:
a1=1, a2=2, a3=3 # fun(*nums) result
a1=4, a2=5, a3=6 # fun(**kwnums) result
```
上面的例子唯一要注意的是,`kwnums`中的key必須為**字串**
### Lambda Function
> 這招必學,學會程式碼可以非常簡短!!
#### Lambda Syntax
```python=
lambda [arg1 [, arg2 [,..., argN]...]] : Lambda Body
```
關於Lambda的一些重點:
1. Lambda 為一匿名函數
2. Lambda 的參數可以有或沒有
3. Lambda Body~~只能有一行~~ one expression(?? diff expression statement)
4. Lambda Body不需要寫Return
- 事實上,可以看成`lambda args : return Lambda Body`
- 一樣的概念,如果你的Body像是print(),就是回傳None
5. Lambda Body不能做Assign
- ?? 目前不清楚為什麼,剛好寫程式有碰到
繼續之前,釐清觀念會更好(內含我自己的推測,請不要全盤接受,盡量挑錯):
> 還記得之前說過,變數為一物件的參考(在Fundamental Concept 第三點)。
> 經過我的觀察,函數也可以用相同的概念來看。
>
```python=
# 先進到Python Interpreter
def f():
return 1
# type f
<function f at 0x00000217D65C52F0>
# 網路上沒找相關資訊但我推測後面的數字應該會是記憶體位置
# 我是由 0x + 碼數16位 + python interpreter 64 bits 判斷
# 可以看到函數的行為是被存在一個固定的地方
# f 只是一個變數,它參考到這塊記憶體位址
# 進行以下測試
g = f
f = 0
# type g
<function f at 0x00000217D65C52F0>
# type f
0
# type g()
1
# 其實可以看到我們的function name是甚麼根本沒差
# 重要的是只要參考到我們要的記憶體位址(或是說函式物件),就夠了
# 額外補充()在此用作 function call operator
```
:::info
結論:
funcion name如同變數一樣,它們都是一個名稱,都可以參考到一個物件,
只是funcion name一開始被定義時,稍微特別一點,它參考到的物件可以執行`()`
:::
進入主角
```python=
# 先進入Python Interpreter
# 這個函式行為跟上面是一樣的,希望可以看得出來
# type lambda : 1
<function <lambda> at 0x00000217D65C5488>
# 到這裡,你可能已經看出來了
# 當我們輸入 lambda : 1 時
# 事實上就是定義了一個函式的行為,並且已經被存在某個記憶體空間了
# 剛剛說了名字是甚麼根本不重要,重要的是我們需要掌握這一塊記憶體位址,才能執行函數行為
# 因此底下提供兩種做法
# 1. 這個函式只會在"現在"用到,並且只會使用一次,那就直接呼叫吧
(lambda : 1)()
# 2. 這個函式"未來"會用到,給它一個變數名稱吧
f = lambda : 1
f()
# 發現了嗎,第二點的使用方法跟以前一模一樣阿
# 難道是我在跟你開玩笑?
# 不,能用一行解決的事,為什麼要寫兩行
```
:::info
結論:
就跟你說學會這招可以簡短程式碼了吧。
思考一下如果有參數的lambda,用兩種寫法該怎麼表示。
不要往下滑,有答案!!
:::
Lambda Example
```python=
# 該筆記的Data Structure中List、Dict
# 使用sort時,很常用到Lambda,底下都有範例
# 在此不贅述
seq = [-4, -3, 5, 7, 9]
filter_res = list(filter(lambda x : x < 0, seq))
# filter_res = [-4, -3]
map_res = list(map(lambda x : x**2, seq))
# map_res = [16, 9, 25, 49, 81]
# 未來寫視窗會用到
# 在tkinter中的按鈕,預設command是不能帶參數的
# 如果要帶參數怎麼辦?
def btn_handler(arg):
pass
btn = tkinter.Button(..., command=lambda:btn_handler(x)).pack()
# 公布解答
# 1. 帶參數直接呼叫
(lambda x, y, z : x*y*z)(3,6,9)
# 2. 存起來日後可以用
f = lambda x, y, z : x*y*z
f(3,6,9)
```
### Try & Test
T1: Raise **ValueError**, Message is "too many values to unpack"
> 所以如果不知道會回傳幾個參數,就用一個變數去取,型別為Tuple;不然就必須要用剛好的變數去取
T2: 參考寫法,歡迎貢獻更多不一樣的寫法
```python=
fun(1,2,3,4,5,6,7,8,9,10)
# 改成
fun(*tuple(range(11)))
# 只想加奇數
fun(*[x for x in range(11) if x%2])
```
T3: 答案是沒有問題
> 按照我的理解,list & tuple的差別應該只是
> list is mutable
> tuple is imutable
### Inbulit Function
1. `abs(num)`
- Return the absolute value of `num`
2. `sum(iterable, start=0)`
3. `id(obj)`
- Return a **unique** number(not address) about the `obj`
4. `type(obj [, base, dict])`
- `type(obj)` Return the class name of the obj
- `type(obj, base, dict` Create a new class
5. `int(n) float(n)`
6. `oct(n) hex(n)`
- Return type is string
7. `complex(real=0, imag=0)`
8. `str(x) bytes(x)`
9. `list(iterable) tuple(iterable) dict(iterable)`
- 底下Inbuilt Data Structure有介紹
10. `isinstance(obj, class | tuple)`
- 可以判斷obj是否為該class或是該class的子類別
- Return boolean
## I/O
### Simple I/O
```python=
'''Input'''
# 讀取資料,直到EOF,回傳型別為字串
data = input()
data = input('Input Prompt')
'''Output'''
print(var1, var2, var3, sep='&') # 預設會自動隔一個空格,透過sep指定
print(var1, var2, end='')
# 預設print一次會自動接一個\n,可以透過end指定以空字串結尾(kwargs的用法)
```
### File I/O
1. 開啟檔案: 使用 open 內建函式
- [更詳細的參數用法](https://docs.python.org/3/library/functions.html?highlight=open#open)
- 基本會用到的參數
- file
- 必要
- 為一絕對、相對的檔案路徑
- 型別為字串
- mode
- Default is `'r'`
- 非必要,但一般都會填
- 開啟檔案的模式
- `'r'` : read only
- `'r+'` : read and write, no Truncation
- `'w'` : write only, Truncation
- `'w+'` : read and write, Truncation
- `'a'` : append, always append before EOF
- `'b'` : binary
- `'rb'`、`r+b` : no Truncation
- `'wb'`、`'w+b'` : Truncation
- 型別為字串
- encoding
- 非必要,偶爾會需要用到
- 型別為字串
- 回傳一檔案物件,利用此物件進行File I/O
> Truncation : 開啟檔案時會把原本檔案刪掉
2. 檔案物件(以下簡稱 f_obj)
- 常用屬性
- `f_obj.closed`
- Return Ture if f_obj is closed
- `f_obj.name`
- Return file name
- `f_obj.mode`
- Retrun file open mode
- 常用函式
- `f_obj.close()`
- 關閉檔案物件
- 當檔案物件的參考(變數)參考到其他檔案物件時,python會自動關閉檔案
- `f_obj.read([count])`
- 讀取檔案內容
- count 為要讀取多少 bytes
- 沒有指定參數,則會盡可能地讀全部的資料
- Return string
- Return `''` if reached EOF
- `f_obj.readline()`
- 讀取資料直到`'\n'`
- Return string
- Return `''` if reached EOF
- `f_obj.readlines()`
- 讀取整個檔案
- Return **list**
- 等同於 `f_obj.read().split('\n')`
- 等同於 `list(f_obj)`
- `f_obj.write(string or bytes)`
- 將資料寫入檔案
- 寫入的資料不是string就是bytes(看模式)
- Return bytes which are written successfully
```python=
# 分享一個曾經看過的寫法
f_obj = open('example.txt', 'r')
for line in f_obj:
print(line, end)
f_obj.close()
```
這樣的好處我想應該是可以節省資料的儲存空間
## Class and Object
### Basic Class Prototype
```python=
class ClassName(object):
def __init__(self, args):
# Initialize data members
self.public_data # No underline
self._protected_data # Single underline
self.__private_data # Double underline
def __del__(self):
# Destructor
pass
def func(self):
# Define member function
pass
def __private_func(self):
pass
```
1. Class 一般名稱開頭會大寫
2. Class 的每個member function第一個參數一定要是self
- self 指的就是該類別本身
- 在class內部存取自己的data member都要透過self
3. `__init__` 相當於建構元,用於初始化data member
- 在Python建立物件的流程,事實上是,`__new__ -> __init__`
4. `__del__` 相當於解構元(我還沒用過)
5. 關於`public、protected、private`
- Python 並沒有實作太多這樣的存取機制(protected 不常見到,一般最多就publice、private)
- Default 都是public
- 若要private,前面加雙底線
6. `class ClassName(object):` 可以寫成 `class ClassName:`
- 後面繼承會談到
```python=
def getGender(self):
return self.gender
class Person:
""" This is Person class description """
def __init__(self, name, gender, age=18):
self.name = name
self.gender = gender
self.__age = age
# 提供我知道的一些方法
def showName(self):
print(self.name)
getAge = lambda self : self.__age
getGender = getGender
Mary = Person('Mary', 'woman', 20)
# Class 往下如果是一個多行註解,它會變成該class的說明文字
# 也可以在help(Person)、help(Mary)查看該說明內容
print(Person.__doc__, Mary.__doc__)
# 示範使用member function
Mary.showName()
print(Mary.getGender(), Mary.getAge())
# Raise AttributeError
print(Mary.__age)
```
### Inheritance
```python=
# Single Inheritance
class SuperClass:
pass
class SubClass(SuperClass):
def __init__(self, args)
# 兩種方式呼叫父類別建構元
super().__init__(args)
SuperClass.__init__(self, args)
# Multiple Inheritance
class SubClass(Class1, Class2, ...):
pass
```
### Polymorphism
### Opeartor Overloading
![](http://1.bp.blogspot.com/-FnIuZ0OPYk8/VcJSm4w254I/AAAAAAAAIpA/Y6_3b2r53TA/s1600/operator_overloading.PNG)
- `int() <=> __int__(self)`
- `float() <=> __float__(self)`
- `str() <=> __str__(self)`
- `[index] <=> __getitem__(self, index)`
- `in <=> __contains__(self, other)`
- `len <=> __len__(self)`
```python=
# 剛好以前有作業有用到
# Inheritance、Operator Overloading、Override
# 暫且拿來當例子ㄅ
# 題目為用現成的PriorityQueue實作Reverse
import queue
# 該Class用來封裝資料,目的是要使用自定義的比大小方式
# 藉此達到Reverse
class Wrapper():
def __init__(self, data):
self.data = data
getValue = lambda self : self.data
# >
def __ge__(self, other):
if isinstance(other, Wrapper):
return not self.data >= other.data
else:
raise TypeError
# >=
def __gt__(self, other):
if isinstance(other, Wrapper):
return not self.data > other.data
else:
raise TypeError
# <
def __le__(self, other):
if isinstance(other, Wrapper):
return not self.data <= other.data
else:
raise TypeError
# <=
def __lt__(self, other):
if isinstance(other, Wrapper):
return not self.data < other.data
else:
raise TypeError
# ==
def __eq__(self, other):
if isinstance(other, Wrapper):
return self.data == other.data
else:
raise TypeError
# 該class繼承了現有PriorityQueue
# 並對put、get兩個function做改寫
# 將送進去儲存的資料用上面的class包裝起來
class MyPriorityQueue(queue.PriorityQueue):
def put(self, data):
super().put(Wrapper(data))
def get(self):
return super().get().getValue()
# 測試函式
if __name__ == '__main__':
pq = MyPriorityQueue()
aList = [5,6,73,1,42,3,9,75]
for e in aList:
pq.put(e)
while True:
if not pq.empty():
print(pq.get(), end=' ')
else:
break
```
## String
### String Function
> Cause string is immutable object, any function changing the string always return a new string object.
#### 1. Test Function
- `isalnum()`
- Return True, if string only contains number or alphabet
- `isalpha()`
- Return True, if string only contains alphabet
- `isdigit()`
- Return True, if string only contains number
- `isspace()`
- Return True, if string only contains whitespace charactor
- `isidentifier()`
- Return True, if string is python identifier
- `islower()`
- Return True, if string is lower case
- `isupper()`
- Return True, if string is upper case
- `startswith(s)`
- Return True, if string starts with `'s'`
- `endswith(s)`
- Return True, if string ends with `'s'`
#### 2. Search Function
- `find(s)`
- Return the first found index of `'s'` in the string which starts from index 0
- Return -1 if `'s'` is not in stirng
- `rfind(s)`
- Return the first found index of `'s'` in the string which starts from last index
- Return -1 if `'s'` is not in stirng
- `count(s)`
- Return how many times `'s'` appers in the string
#### 3. Common Function
- `lower()`
- Return string is lower case
- `upper()`
- Return string is upper case
- `replace(old, new)`
- Return string has replaced old sub_string to new sub_string
- EX:`str.replace('\n', '').replace('\r', '').replace('\t', '')`
- `split(sep=None, maxsplit=-1)`
- Return a list of the words in the string, using sep as the delimiter string.
- EX:`'He ll o'.split(' ') --> ['He', 'll', 'o']`
- `join(iterable)`
- Return a new string that inserted string between the each element in the iterable
- EX:`','.join(['He', 'll', 'o']) --> 'He,ll,o'`
- `string.strip()`
- Return a new string that striped the blank or string you assigned
```python=
string = """ geeks for geeks """
# prints the string by removing leading and trailing whitespaces
print(string.strip())
# prints the string by removing geeks
print(string.strip(' geeks'))
```
#### 4. Format Function
> 不熟,待補充
兩個常用形式:
```python=
name, age = 'Tom', 8
str1 = "I'm {}, {} years old.".format(name, age)
str1 = "I'm {1}, {0} years old.".format(name, age)# output = I'm 8, Tom years
str1 = "I'm {:^8}, {:*>3} years old.".format(name, age)
'''
^ 置中; >, 靠右; <, 靠左
'''
str2 = f'I\'m {name}, {age} years old.'
str3 = "%s is %d years old." % (name, age)
```
## Exception Handling
### Basic Type
```python=
# 觸發例外
raise <ExceptionType>
# 處裡例外
try:
<body>
except <ExceptionType1>:
<handler1>
...
except <ExceptionTypeN>:
<handlerN>
except:
<handlerExcept>
# 當前面的except都無法抓到合適的型態時, 執行此區塊
else
<process_else>
# 當try裡面沒有例外發生時, 執行此區塊
finally:
<process_finally>
# 定義一些收拾行為, 不管有沒有發生例外, 最後都會執行此區塊
```
## Inbuilt Data Structure
### List
> List is a mutable object.
> List is like one dimension array, more like vector in C/C++
#### 1. List Functions
- `list.append(elem)`
- Append elem to the tail of list
- `list.extend(iterable)`
- Extend the iterable and append all elems of it to the list
- EX: `[1,2].extend( (4,5) ) --> [1,2,4,5]`
- `list.insert(idx, elem)`
- Insert the elem to the idx
- EX: `[1,3,4,5].insert(1,2) --> [1,2,3,4,5]`
- `list.remove(elem)`
- Remove the **first** elem in the list
- Raise ValueError if elem is not in the list
- EX: `[1,2,1].remove(1) --> [2,1]`
- `list.pop([idx])`
- Remove the idx-th elem
- Remove the last elem if no idx
- `list.clear()`
- Clear all elems from the list
- Same as `del list[:]`
- `list.index(elem, [start [, end]])`
- Return the idx of the **first** elem
- Raise ValueError if elem is not in the list
- `list.sort(key=None, reverse=False)`
- Sort the list by key
- In-place Sort
- `list.copy()`
- Return the copied list
```python=
# Sort Example
# Initialize var
a = [9, 4, 7, 1]
a.sort()
## a = [1,4,7,9]
# Initialize var
b = [ (1, 'FC'), (-9, 'XY'), (4, 'KC'), (11, 'BZ') ]
# sort by default
# Try & Test & Think, What is default
b.sort()
## b = [(-9, 'XY'), (1, 'FC'), (4, 'KC'), (11, 'BZ')]
# sorted by 'word'
b.sort(key=lambda x : x[1])
## b = [(11, 'BZ'), (1, 'FC'), (4, 'KC'), (-9, 'XY')]
# sorted by the second character of the 'word'
b.sort(key=lambda x : x[1][1])
## b = [(1, 'FC'), (4, 'KC'), (-9, 'XY'), (11, 'BZ')]
```
```python=
# Four ways of copy
# Initilize var
a = [1,2,3]
# Copy
# Bad Way
b = []
for x in a:
b.append(x) or b.insert(len(b), x)
# Better Way
b = a.copy() # Use list copy function
b = [] + a # Use list concatenation
b = [x for x in a] # Use list comprehension
# Try & Test & Think
# Why don't we simply use
b = a
```
#### 2. List Slicing
> List 可以一次取出不只一個元素,用的就是 Slicing
##### Syntax
```python=
list[index1 : index2] #從index1取到index2(不包含index2)
```
##### Example
```python=
x = [1, 2, 3, 4]
x[0:2] # [1, 2]
x[1:-1] # [2, 3], 1和倒數第一個之間的元素
x[2:0] # [] , 若第一個索引的位置在第二個索引的位置之前
x[ :2] # [1, 2], 從開頭開始切
x[2: ] # [3, 4], 從2開始切到尾
x[ : ] # [1,2,3,4], 這邊是不一樣的list只是切出所有元素
```
#### 3. List Comprehension
> 這招必學,學會程式碼可以非常簡短!!
##### Basic Type
```python=
list_var = [ x for x in iterable ]
a = [1, 3, 5]
b = [x for x in a]
## b = [1, 3, 5]
apple = [c for c in 'apple']
## apple = ['a', 'p', 'p', 'l', 'e']
```
##### With Condition
```python=
odd_num = [n**2 for n in range(10) if n % 2]
## odd_num = [1, 9, 25, 49, 81]
# Equal to
odd_num = []
for n in range(10):
if n % 2:
odd_num.append(n**2)
# Nested If
nums = [n for n in range(100) if n % 2 == 0 if n % 5 == 0]
## nums = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
# Equal to
nums = []
for n in range(100):
if n % 2 == 0:
if n % 5 == 0:
nums.append(n)
```
##### With Nested Loop
```python=
nums = [ x*y for x in [1,2,3] for y in [10,20,30] ]
## nums = [10, 20, 30, 20, 40, 60, 30, 60, 90]
# Equal to what?
# Try & Test
```
#### 4. List Common Usage
```python=
# 1. Transform input to int
nums = list(map(int, input('Input Numbers: ').split(' ')))
# 2. Access elems dirtectly, not access by index
for elem in aList:
pass
# 3. Get list size
size = len(aList)
# 4. Delete element in list
aList = ['a', 'b', 'c', 3, 4, 5]
del aList[1] # aList == ['a', 'c', 3, 4, 5]
del aList[ :2] # aList == [3, 4, 5]
```
#### 5. List Common Error
```python=
aList = list(1, 2, 3)
## Raise TypeError
# Create a list just simply use
aList = [1, 2, 3]
# list(iterable) correct usage
aList = list( (1, 2, 3) )
aList = list( range(1,4) )
```
### Tuple
> 1. Tuple is a immutable object
> 2. Common usage is to store value
> 3. Can't insert value to the tuple and remove value from the tuple
### Dictionary
> 1. 使用key-value的方式儲存資料
> 2. 如同C++ hash map
> 3. key-value可以為任意型別
#### 1. Dictionary Function
- `dict(mapping)`:
- Return the dict of mapping
- EX:`dict([('one', 1) ,('two', 2)]) --> {'one': 1, 'two': 2}`
- `dict(**kwargs)`:
- EX:`dict(k1='A', k2='B') --> {'k1': 'A', 'k2': 'B'}`
- `[]`:
- Add the value to the key
- EX: `dict_obj[key] = value`
- Get the value of the key
- EX: `var = dict_obj[key]`
- If no key, raise KeyError
- `dict.update(**kwargs or dict_obj)`
- Add the value to the original dict_obj
- `dict.clear()`
- Remove all elems in the dict
- `dict.copy()`
- Return the copy of the dict
- `dict.get(key, default=None)`
- Return the value of the key
- If no key, return default
- EX:`dict.get(fun, lambda:print('no fun'))()`
- `dict.keys()`
- Return a list of the key in dict
- `dict.values()`
- Return a list of the value in dict
- `dict.items()`
- Return a list of the key-value pair in dict
- `dict.pop(key, [default])`
- Return the value of the key, and pop the key from the dict
- If key isn't exist, return default
- If no default , raise KeyError
- `dict.__contain__(key)`
- Return True if key in the dict
- EX:`True if key in dict else False`
#### 2. Dictionary Example
```python=
# dict example with sorted and lambda
dic = {'Mary' : 50, 'Bob': 30, 'Cindy' : 80, 'John' : 100, 'Can' : 10}
# Sort by key
sort_by_key = sorted(dic.items(), key = lambda x:x[0])
## sort_by_key =
## [('Bob', 30), ('Can', 10), ('Cindy', 80), ('John', 100), ('Mary', 50)]
# Sort by value
sort_by_val = sorted(dic.items(), key = lambda x:x[1])
## sort_by_val =
## [('Can', 10), ('Bob', 30), ('Mary', 50), ('Cindy', 80), ('John', 100)]
# Sort with the second word of name and reverse
sort_ch = sorted(dic.items(), key = lambda x:x[0][1], reverse = True)
## sort_ch =
## [('Bob', 30), ('John', 100), ('Cindy', 80), ('Mary', 50), ('Can', 10)]
```
## Module -- JSON
> Library: json
常用函式:
1. `dump(obj, fp)`
- Python物件轉換成JSON格式字串,並寫入檔案
2. `loda(fp)`
- 從檔案讀取JSON,並轉換成Python物件
3. `dumps(obj)`
- 注意s,將Python物件轉換成JSON格式字串
- 選用參數(有很多,僅列出我用過的)
- skipkeys
- default = False
- True,略過非Python基本型態的key值,(Python基本型態:str、int、float、bool、None)
- False 遇到非Python基本型態的key值,產生TypeError
- sort_keys
- default = False
- 按照資料key值排序
- separators
- default = None
- If None 預設字典顯示,為`( ' , ' , ' : ' )`,代表每對pair之間用逗點隔開,key與value之間用冒號隔開
- EX:`json.dumps( { 1 : 'Mary', 2: 'Jack' }, separators=(" | ", " = ") )`
- Output:`'{"1" = "Mary" | "2" = "Jack"}'`
4. `loads(str)`
- 注意s, 將JSON字串轉換成Python物件
型別對照表
| Python | JSON |
|:------:|:------:|
| dict | object |
| str | string |
| int | number(int) |
| float | number(real) |
| True | true |
| Flase | flase |
| None | null |
使用範例
```python=
# 進入Python Interpreter
import json
# 基本型態
a, b, c, d, e, f = 'Hi', 10, 1.0, True, False, None
# dumps function
A = json.dumps(a)
B = json.dumps(b)
C = json.dumps(c)
D = json.dumps(d)
E = json.dumps(e)
F = json.dumps(f)
# type A ~ F,觀察結果
# loads funcion
a1 = json.loads(A)
b1 = json.loads(B)
c1 = json.loads(C)
d1 = json.loads(D)
e1 = json.loads(E)
f1 = json.loads(F) # 用print才看得到
# type a1 ~ f1,觀察結果
# 可以測試一下,a == a1 ~ f == f1,結果都會是True
```
:::info
小結: 基本型態的轉換可以放心使用,沒有問題
:::
```python=
# 進入Python Interpreter
import json
# 資料結構 Tuple List Dictionary
aTuple = ('Tuple', 'will', 'change', 'toList', 99)
aList = ['Int', 10, 'Float', 1.0, 'String', 'hello', 'LofL', [1,2], (3,4)]
aDict = {9 : 99, 1.0 : 5.5, 'str' : 'string', None : None}
# dumps function
TD = json.dumps(aTuple)
LD = json.dumps(aList)
DD = json.dumps(aDict)
# type LD TD DD,觀察結果
# loads function
bTuple = json.loads(TD)
bList = json.loads(LD)
bDict = json.loads(DD)
# type (a、b) pair 比較結果
# 可以測試一下,每對pair的比較,結果都會是Flase
```
:::info
小結: 資料結構的轉換必須要注意一些事情
1. List 在轉換時只要其元素都為基本型態,是沒問題的
2. JSON 沒有Tuple的型態,任何Tuple都會被轉成List
3. Dictionary 的key在JSON裡面必須是字串型態,value不受影響
:::
如果一定要非字串型別當作dict key值的話,可以使用二次dump的技巧
```python=
def transKey(dict_data, encode=True):
tmp_dict = {}
for key, value in dict_data.items():
if encode:
tmp_dict[json.dumps(key)] = value
else:
tmp_dict[json.loads(key)] = value
return tmp_dict
# 使用上
aDict = {9 : 99, 1.0 : 5.5, None : None}
# 先進行key轉換,在做dumps
aDict_transKey = transKey(aDict, encode=True)
jDict_dump = json.dumps(aDict_transKey)
# 先做loads,再將key轉回去
jDict_load = json.loads(jDict_dump)
bDict = transKey(jDict_load, encode=False)
if aDict == bDict:
print('Successed!!')
```
Json 和檔案相關的簡單基本操作
```python=
# Json & File
aDict = {'1' : 'one', '2' : 'two', '6' : 'six'}
# 寫入檔案(法一)
with open('example.json', 'w') as fp:
fp.write(json.dumps(aDict))
# 寫入檔案(法二)
json.dump(aDict, open('example.json', 'w'))
# 讀出檔案(法一)
with open('example.json', 'r') as fp:
data = json.loads(fp.read())
# 讀出檔案(法二)
data = json.load(open('example.json', 'r'))
```
## Third Party Module
```python=
# Download Module
pip install <module name>
# Update Module
pip install -U <module name>
```
```python=
# 下載過的模組
pyperclip # 剪貼簿(複製、貼上)
openpyxl # Excel 相關操作
```
### Module -- Pyperclip
> library pyerclip
- copy(*string*)
- 傳送字串到剪貼簿
- paste()
- 從剪貼簿接收字串
### Module -- Openpyxl
> library openpyxl
> 用來處理Excel檔案
#### Excel
- Excel 試算表文件 == 活頁簿(workbook)
- 儲存在.xlsx檔案中
- 活頁簿可有多個工作表(sheet)
- 正在使用的工作表稱為 active sheet
- 欄從A開始
- 列從1開始
#### Attr & Fun
##### openpyxl
- load_workbook(*file*)
- file 為 Excel 檔名
- Return: Workbook Object
```python=
wb = openpyxl.load_workbook('examply.xlsx')
```
- Workbook()
- 建立空的活頁簿
- Return: Workbook Object
##### openpyxl.utils
- get_column_letter
- 將數字轉成欄位代碼
```python=
openpyxl.utils.get_column_letter(27) #AA
```
- column_index_from_string
- 將欄位代碼轉成數字
```python=
openpyxl.utils.column_index_from_string('AA') # 27
```
##### openpyxl.styles
- Font(*name, size, bold, italic*)
- 可以自訂儲存格字型別樣式
- name : 字型名稱, `string`
- size : 字型大小, `int`
- bold : 粗體, `bool`
- italic : 斜體, `bool`
```python=
from openpyxl.styles import Font
f1 = Font(name='Console', size=12, bold=true, italic=true)
<cell>.font = f1
```
##### workbook
- active
- 取得 active sheet
- Return: Worksheet Object
- worksheets
- 取得所有 sheets
- Return: List
- encoding
- 取得編碼
- Return: String
- get_sheet_by_name(*sheet name*)
- 取得指定 sheet
- Return: Worksheet Object
- get_sheet_names()
- 回傳所有的sheet
- Return: List
- create_sheet(*index=, title=*)
- 建立分頁,預設加在最後,可以指定index
- remove_sheet(*Sheet Objet*)
- 刪除指定的分頁
- save(*excel name*)
- 儲存成Excel檔
##### Worksheet
- title
- 取得 sheet name
- max_row
- 取得工作表列的最大值
- max_column
- 取得工作表行的最大值
- freeze_panes
- 設定凍結窗格(不管捲到哪,都會顯示在最上層)
- 需要注意的是,凍結的範圍是**小於給定的值**
- A1 -> 沒有凍結
- 等同於`None`
- B2 -> 凍結欄A、列1
- C1 -> 凍結欄A、欄B
```python=
ws.freeze_panes = 'A2'
```
- row_dimensions[*row*].[height | width]
- 設定指定列的高度或寬度
```python=
ws.row_dimensions[1].height = 50
```
- column_dimensions[*row*].[height | width]
- 設定指定行的高度或寬度
```python=
ws.column_dimensions['B'].width = 15
```
- cell(*row=i, column=j*)
- 取得i列j行的儲存格
- Return: Cell Object
```python=
# 另外一種取法
sheet['A1'].value
```
- merge_cells(*range*)
- 合併儲存格
```python=
ws.merge_cells('A1:D3') # merge 12 cells
```
- unmerge_cells(*range*)
- 取消合併儲存格
```python=
ws.unmerge_cells('A1:D3') # merge 12 cells
```
##### cell
- value
- 取得值或修改值
- row
- 取得該cell位於哪一列
- column
- 取得該cell位於哪一行
- coordination
- 取得該cell位置(EX: A1、B2)
##### Sheet Slice
```python=
import openpyxl
wb = openpyxl.load_workbook('example.xlsx')
st = wb.get_sheet_by_name('Sheet1')
for row in sheet['A1':'C3']:
for cell in row:
print(cell.coordinate, cell.value)
```
##### Formula
> Excel中公式是由=開頭
```python=
import openpyxl
wb = openpyxl.Workbook()
ws = wb.actice
ws['A1'], ws['A2'] = 100, 200
ws['A3'] = '=SUM(A1:A2)'
wb.save('formula.xslx')
```
##### Example
###### Chart
```python=
import openpyxl
wb = openpyxl.Workbook()
ws = wb.active
# Create simple data in cell
for i in range(1,11):
ws['A'+str(i)] = i
# Create Reference Object
ref = openpyxl.chart.Reference(ws, min_col=1, min_row=1, max_col=1, max_row=10)
# Create Series Object
series = openxl.chart.Series(ref, title='First series')
chart = openpyxl.chart.BarChart() # 直方圖
chart.title = '直方圖'
chart.append(series) # 將序列資料加到圖表中
ws.add_chart(chart, 'C5') # 將圖表加到分頁中指定的位置
wb.save('sammpleChart.xlsx')
```
:::danger
雖然openpyxl可以製作圖表,但在讀取Excel時,無法讀取圖表
:::
- 其他可畫的圖表
- openpyxl.chart.LineChart(), 折線圖
- openpyxl.chart.ScatterChart(), 散佈圖
- openpyxl.chart.PieChart(), 圓餅圖