comment:
single line: #multiple line: ''' ... '''
encode: # -*- coding: utf-8 -*-
math operation:
- 先乘除後加減
- 5**2: 5 的平方
- 5**0.5: 平方根
- log(8, 2) => 3
Data type
- None 就是 C 的 null
- 變數型態不需宣告
- only int, float, string
- string
- 'mystring'
- mychar = string[0] #mychar is still string type
- string[2:5]
- s[2] == 'a'
- s += "append string"
- array/linked-list/stack (implemented by array)
- fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
- len(fruits)
- fruits.count('apple') => 2
- fruits.index('banana') => 3
- fruits.index('banana', 4) => 6
- fruits.remove('banana')
- del fruits[-1]
- fruits.insert(3, 'grape')
- fruits.reverse()
- fruits.append('grape')
- fruits += ['orange', 'peach']
- fruits.sort()
- fruits.pop() => 'banana'
- nD
- 2D array 取值是用 a[i][j],不是用 a[i, j],後者回傳的是 tuple
- 可用 a[i][j:j+n] 取一截 list,但不可用 a[i:i+n][j:j+n] 取一塊矩陣
- sum(list) 可用於取 list 的總和,但只能 1D
- seq[start:end:step]
- max(list)
- queue
- from collections import deque
- myq = deque(['A', 'B', 'C', 'D', 'E'])
- myq.append ('F') => deque(['A', 'B', 'C', 'D', 'E', 'F'])
- myq.popleft() => 'A'
- if q: # check if its empty queue
- tuple (不可變動的 list)
- tp1 = ()
- tp2 = (1, 2, 3, 4, 5)
- len(tp2) => 5
- sum(tp2) => 15
- tp2[2:4] => (3, 4)
- tp2[-1] => 5
- tp3 = tuple([2 * x for x in range(1, 8)]) => (2, 4, 6, 8, 10, 12, 14)
- print(tuple('Ivy Lin')) => ('I', 'v', 'y', ' ', 'L', 'i', 'n')
- tp2 + tp3 => (1, 2, 3, 4, 5, 2, 4, 6, 8, 10, 12, 14)
- tp4 = tuple([1, 2, 3, 4, 5]) => (1, 2, 3, 4, 5)
- max(tp4) => 5
- min(tp4) => 1
- list(tp2) => [1, 2, 3, 4, 5]
- tp2 == tp4 => true
- dictionary
- dic = {'key1': 22, 'key2': 42}
- dic[key3] = 333
- for i in sorted (dic.keys()):
print(dic[i]) - if key in dic:
- dict 不可迭代,可使用 next(iter(dict)) 幫助先轉換成可迭代
或者使用 for k, v in dict.items() - sorted_x = sorted(x.items(), key=lambda kv: kv[1])
sorted_x will be a list of tuples sorted by the second element in each tuple.
print('...', '...', ...)
- 若要不換行,指定 end 參數 print('...', end=' ')
- sep 參數指定每個參數之間 print 時的分隔字元
- 也有類似 C 的方式:print('%d %.2f %s' % (1, 99.3, 'Justin'))
% 符號之後要接一個 (tuple) - f-string (3.6 以後支援)
>>> stock = 'tsmc'
>>> close = 217.5
>>> f'{stock} price: {close}'
'tsmc price: 217.
stderr
def eprint(*args, end='\n', **kwargs):
print(*args, file=sys.stderr, end=end, **kwargs)
i = i - 1
Loop
for
for _ in range(n) # 執行 n 次,底線代表不在意
for i in range (0, n) # 執行 n 次,i 會從 0 到 n-1
for i in range (n, -1, -1) # 執行 n+1 次,i 會從 n 到 0
for m in iterable_object # m 會依序為可迭代物件的 member
for i in range (0, n) # 執行 n 次,i 會從 0 到 n-1
for i in range (n, -1, -1) # 執行 n+1 次,i 會從 n 到 0
for m in iterable_object # m 會依序為可迭代物件的 member
- 用於定義物件
mylist = [i for i in range(0, 5)]
while
while i > 0:i = i - 1
print('append ', a[i])
b = array('i')
b.fromlist(list)
sorted_list = sorted(list)
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10),
]
sorted(students, key = lambda x : x[2]) # x 為 iterable 中的每個元素,作為參數傳入 lambda,lambda 定義的 expression 為 x[2] 即為結果回傳
Condition
- if:
elif:
else: - .. if ... else ... # 三元運算子
- "is" is used for checking reference equality
Function
def reverseArray(a):
return a
- 若 function 內要使用到全域變數,需加上 "global" 宣告
- python 無法指定參數傳值或傳址,是其可變形態而定
- 不可變,相當於傳值:數字,字串,元組
- 可變,相當於傳址:列表,字典
- 實際上 def 是個陳述句,Python 執行到 def 時會產生一個函式物件,為 function 的實例,即然函式是個物件,它可以指定給其它的變數
- Python 不支援重載,在同一個名稱空間中,不能有相同的函式名稱。如果定義了兩個函式具有相同的名稱但擁有不同的參數個數,則後者定義會覆蓋前者定義
- 指定可變動物件陷阱
>>> def appendTo(element, arr = []):
... arr.append(element)
... return arr
>>> appendTo(10)
[10]
>>> appendTo(20, [4, 5, 6])
[4, 5, 6, 20]
>>> appendTo(20) # 這個串列是在 def 時就已經被創立
[10, 20]
def sum(*numbers):
- 不定長度引數,傳入函式的引數,會被收集在一個 Tuple 中,再設定給 numbers
- 如果有個函式擁有固定的參數,也可以將一個 Tuple 傳入,只要在傳入時加上*,則 Tuple 中每個元素會自動指定給各個參數
def sum3(a, b, c):
return a + b + c
numbers = (1, 2, 3)
print(sum3(*numbers))
>>> def dosome(**args):
... print(args)
>>> dosome(name = 'Justin', passwd = 123456, job = '?')
{'passwd': 123456, 'job': '?', 'name': 'Justin'}
- **則可以將關鍵字引數收集在一個字典物件中
- 同理,如果函式參數個數固定,也可以傳給函式一個字典物件,只要在物件前加上**,則 Python 會依字典物件的鍵名稱,將值指定給對應名稱的參數
def sum3(a, b, c):
return a + b + c
args = {'a' : 1, 'b' : 2, 'c' : 3}
print(sum3(**args)) - 可以在一個函式中,同時使用*與**
>>> def some(*arg1, **arg2):
... print(arg1)
... print(arg2)
>>> some(1, 2, 3)
(1, 2, 3)
{}
>>> some(a = 1, b = 22, c = 3)
()
{'a': 1, 'c': 3, 'b': 22}
>>> some(2, a = 1, b = 22, c = 3)
(2,)
{'a': 1, 'c': 3, 'b': 22}
- *arg1 必須要在 **arg2 的前面,因為 *arg1 搜集的是有順序感的參數
def fun(a, *args, **kwargs):
print("a={}".format(a))
for arg in args:
print('Optional argument: {}'.format( arg ) )
for k, v in kwargs.items():
print('Optional kwargs argument key: {} value {}'.format(k, v))
- 函式中還可以定義函式,稱之為區域函式(Local function),好處之一就是可以直接存取包裹它的外部函式之參數(或宣告在區域函式之前的區域變數),如此可減少呼叫函式時引數的傳遞
- 匿名函式 lambda,就不不需要有名字的暫時使用的函式
lambda 的語法是
lambda arg1, arg2, ....: expression - max = lambda m, n: m if m > n else n
Data Structure
Array
from array import arrayb = array('i')
b.fromlist(list)
Class
class SinglyLinkedListNode:
def __init__(self, node_data):
self.data = node_data
self.next = None
private member/function
會以兩個底線開頭,但基本上只是命明區別,而並非真的 private
def __init__(self, id, name):
super(CheckingAccount, self).__init__(id, name) # 呼叫父類別__init__()
self.overdraftlimit = 30000
def withdraw(self, amount): # 從子類別開始尋找是否有定義,否則就搜尋父類別中是否有定義方法
if amount <= self.balance + self.overdraftlimit:
self.balance -= amount
else:
raise ValueError('超出信用')
def __str__(self):
return (super(CheckingAccount, self).__str__() +
'\nOverdraft limit\t' + str(self.overdraftlimit));
acct = CheckingAccount('E1234', 'Justin Lin')
print(acct, end='\n\n')
acct.deposit(1000) # 使用 Account 的 deposit() 定義
print(acct, end='\n\n')
acct.withdraw(2000) # 使用 CheckingAccount 的 withdraw() 定義
print(acct, end='\n\n')
繼承
class CheckingAccount(Account):def __init__(self, id, name):
super(CheckingAccount, self).__init__(id, name) # 呼叫父類別__init__()
self.overdraftlimit = 30000
def withdraw(self, amount): # 從子類別開始尋找是否有定義,否則就搜尋父類別中是否有定義方法
if amount <= self.balance + self.overdraftlimit:
self.balance -= amount
else:
raise ValueError('超出信用')
def __str__(self):
return (super(CheckingAccount, self).__str__() +
'\nOverdraft limit\t' + str(self.overdraftlimit));
acct = CheckingAccount('E1234', 'Justin Lin')
print(acct, end='\n\n')
acct.deposit(1000) # 使用 Account 的 deposit() 定義
print(acct, end='\n\n')
acct.withdraw(2000) # 使用 CheckingAccount 的 withdraw() 定義
print(acct, end='\n\n')
- 可以進行多重繼承,使用時搜尋正確 func 定義該用誰的,的順序是從子類別開始,接著是同一階層父類別由左至右搜尋,再至更上層同一階層父類別由左至右搜尋,直到達到頂層為止
- 每個類別有個__bases__特性,記錄著所繼承的父類別,__bases__是個 Tuple
I/O
input
input('請輸入你的名稱:') # 從 stdin 取得 input,支援提示字串- int('...'), float('...'), bool('...') 支援將字串轉為其他形態
content = file.read() # 全部讀入
print(content)
file.close()
file = open(name, 'r', encoding='UTF-8')
for line in file.readlines(): # 逐行讀取
print(line, end='')
file.close()
for line in open(name, 'r', encoding='UTF-8'): # for 會嘗試呼叫檔案物件的 next() 方法,next() 方法每次傳回下一行,並在沒有資料可讀取時丟出 StopIteration
print(line, end='')
output
- print(1, 2, 3, file = open('data.txt', 'w')) # file 指定輸出位置,可為 stderr 或實際檔
Error Handling
try:
#嘗試執行的程式碼
except 例外名稱:
#當遇到例外時要執行的程式碼,except 的區塊可以有很多個
try:
a = int(input())
b = int(input())
print(a/b)
except ZeroDivisionError:
print("Cannot divide by 0!")
except:
print("Wrong input")
try:
#嘗試執行的程式碼
except 例外名稱:
#當遇到特定的例外時要執行的程式碼
except:
#當未指定的例外發生時要執行的程式碼
else:
#若 try 當中的程式碼並未產生例外時要執行的區塊
finally:
#無論如何都要執行的程式碼
try:
a = int(input())
b = int(input())
c = a/b
except ZeroDivisionError:
print("Cannot divide by 0!")
except:
print("Wrong input")
else:
print("The answer is " + str(c))
finally:
print("Program finished")
Useful functions
map
Apply function to every item of iterable and return a list of the results- map(int, listA) # return 一個 list 其內容為 listA 中各元素轉換為 int
- print map(multiple2, list1) # multiple2 為一個自定義 func,將 list1 中的各元素作為 multiple2 的參數傳入,得到相應的 multiple2 的回傳值組成一個 list 回傳
- map(adder, list1, list2, list3) # adder 這個 func 有三個參數
sort
list.sort()sorted_list = sorted(list)
- sorted() 會回傳一個排序好新的 list,sort() 會直接修改原始的 list 並排序完成
- sort() 只能用在 list 上排序,而 sorted() 可用來排序任何的 iterable(string, dictionary, tuple...)
- sorted()
- 可指定 reverse 為 True,會把排序的結果由預設的 ascending 改成 descending
- 可設定一個 func 給 key 這個參數,在排序之前會自動對每個 element call 一次所指定的 function,比如將 element 都先轉為 lower case。key 只能接受 function 物件,所以常見藉由 lambda 來提取複雜物件中欲用來 sort 的 key
('john', 'A', 15),
('jane', 'B', 12),
('dave', 'B', 10),
]
sorted(students, key = lambda x : x[2]) # x 為 iterable 中的每個元素,作為參數傳入 lambda,lambda 定義的 expression 為 x[2] 即為結果回傳
- Python 另外有 operator module,可以不用自己撰寫 key 的 function 可以簡單提取複數個物件中的元素作為 key 值
from operator import itemgetter, attrgetter
filter
filter() 函数用于过滤 list,过滤掉不符合条件的元素,返回由符合条件元素组成的新 list。接收两个参数,第一个为 function object,第二个为 list,list 的每个元素作为参数传递给function object 进行判,function 返回 True 或 False,将返回 True 的元素放到新 list 中
Asynchronous I/O
要達成非同步 (Asynchronous) I/O 有很多種策略,常聽到的是使用多執行緒(multithreading) 達到非同步。但另外 python 提供協同程序 (coroutine) 的概念。簡單說協同程序是在 single thread 下允許程式來決定程式執行的順序,而有效達成非同步 I/O 的一種方法。
- 事件迴圈
- 異步程式可以在多個任務之間切換,這個程式的架構裡一定有一個任務 list,這樣程式才知道有什麼樣的任務可以做切換,而這個任務的 list 以及中間切換的機制,就是由事件迴圈 (Event loop) 來處理
- 事件 (Event) 與 回調函數 (Callback)
- 現在 Event loop 裏面有一個 list,若程式有一些任務需要以異步的方式去執行就需要以 "Event:Callback" 的型式註冊進 Event loop 的 list,之後 Event loop 以 for 迴圈的方式去察看 list 裏面的 Event 是否發生,若發生了就執行相對應的 Callback,並註銷這個Event的監聽
- 比如正在監聽的 Event_B 發生了,就會註銷 Event_B 的監聽 (也就是把Event_B從list中移除),然後執行Callback_B,執行完後在繼續監聽剩下的事件
- 協程 (coroutine)
- 協程可以看做是 "能在中途中斷、中途返回值給其他協程、中途恢復、中途傳入參數的函數",和一般的函數只能在起始傳入參數,不能中斷,而且最後返回值給父函數之後就結束的概念不一樣
- 定義協程很簡單,只要在定義函數時再前面加入"async" 這個關鍵字就行了
loop = asyncio.get_event_loop() #建立一個Event Loop
loop.run_until_complete(coroutine)
# 這個函數註冊參數裡的任務並執行,等到任務完成就關閉 Event Loop
# 這裏被註冊進去的事件的定義是 loop 一啟動就直接觸發的,所以 coroutine 裡面的任務內容會馬上執行
loop.run_forever()
# 這個函數一執行,Event Loop 就會永遠執行不會被關閉,除非在程式中出現loop.stop()就停止
import asyncio
loop = asyncio.get_event_loop() #建立一個Event Loop
async def example1(): # 定義一個中間會被中斷的協程
print("Start example1 coroutin.")
await asyncio.sleep(1) # 中斷協程一秒
# 使用await可以針對耗時的操作進行掛起,就像生成器裏的 yield 一樣,函數讓出控制權。協程遇到 await,事件循環將會掛起該協程,執行別的協程,直到其他的協程也掛起或者執行完畢,再進行下一個協程的執行。耗時的操作一般是一些IO操作,例如網絡請求,文件讀取等
print("Finish example1 coroutine.")
async def example2(): # 定義一個協程
print("Start example2 coroutine.")
# do some process...
print("Finish example2 coroutine.")
tasks = [ # 建立一個任務列表
asyncio.ensure_future(example1()),
asyncio.ensure_future(example2()),
]
# 把協程封裝成一個 task 對象,這個對象儲存了任務的 "上下文"(context),協程才能順利的恢復執行,因為暫停時的變數內容都存在 task 對象裡
loop.run_until_complete(asyncio.wait(tasks))
# asyncio.wait():把任務列表都註冊到Event Loop,並要求 Event Loop 必須確定裡面的兩個任務都執行完才能結束 Event Loop 機制
# 把 example1, example2 這兩個 coroutin 註冊到事件循環裡
# loop 啟動,先執行 example1,中途暫停 example1 之後切換到 example2,最後再切回example1
output:
Start example1 coroutine.
Start example2 coroutine.
Finish example2 coroutine.
Finish example1 coroutine.
ref:
https://ithelp.ithome.com.tw/articles/10199403
留言
張貼留言