跳到主要內容

[Coding] Python

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

  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)

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

  • 用於定義物件
    mylist = [i for i in range(0, 5)]

while

while i > 0:
    i = i - 1
    print('append ', a[i])

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 array
  b = array('i')
  b.fromlist(list)

Class

class SinglyLinkedListNode:
    def __init__(self, node_data):
        self.data = node_data
        self.next = None

private member/function

  會以兩個底線開頭,但基本上只是命明區別,而並非真的 private

繼承

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('...') 支援將字串轉為其他形態
  file = open(name, 'r', encoding='UTF-8')
  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 
students = [
        ('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" 這個關鍵字就行了
import asyncio
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


留言

這個網誌中的熱門文章

[Development] git

本篇介紹幾個 git 會用到的基本 command line 指令 安裝 on Mac OS [tested on macOS Catalina 10.15.1] (可以用 Brew 安裝,若尚未安裝 Brew:  https://brew.sh/index_zh-tw ) $ brew install git $ git --version git version 2.21.0 (Apple Git-122.2)   github 官網就有提供 GUI 的應用 ,想用 GUI 的直接去下載安裝就行了,也有簡單明瞭的教學,非常容易。另外也有好幾個第三方的好用 GUI 介面,Google 一下比較一下選自己喜歡的也行。   但以下還是用 command line 的方法來操作,因為這還是最 general 到哪都可以用的基本方法。因為實務上,比如 code 都放在公司的 server,你可能也是都要 ssh 到 sever 上去改 code,改完之後要上傳到 github。而公司的 server 就是一台 Linux 環境,很可能是沒有提供 GUI 讓你使用的,所以你就只能用 command line 的方式完成 git 的上傳。 Create Repo   去本地一個你想要放置 git 專案的地方,比如我想把我之後的 git code 都放在我 Mac local 的 /Users/chungchris/git $ cd /Users/chungchris/git $ git init   就會看到在此 git 目錄下產生一個隱藏的 .git 資料夾,這樣就完成了: (base) Chris-MBP:git chungchris$ ls -al total 0 drwxr-xr-x   3 chungchris   staff     96 11 21 11:01 . drwxr-xr-x+ 53 chungchris   staff   1696 11 21 10:45 .. drwxr-xr-x   9 chungchris   staff  ...

[Coding] Compiler

Something about compiling. #compiler #link #gcc Reference PTT LinuxDev, 作者: cole945 (躂躂..) 看板: LinuxDev, 標題: [心得] 用gcc 自製Library, 時間: Sun Nov 5 04:15:45 2006 Static Link Compile 時將 library 加入程式碼,執行快但佔空間,code size 和 mem 使用都比較多 Compile source codes to generate object files $ gcc -c file1.c file2.c file3.c -c 編出 object 檔 Create a static library named libmylib.a $ ar rcs lib mylib .a file1.o file2.o file3.o 把一堆 object 檔用 ar(archiver) 包裝集合起來,檔名以`.a’ 結尾 Using a Static Library to generate a executable files $ gcc -o main main.c -L. -l mylib -L: the directory of the library. 可以指定多次 -LDIR -l: the name of the library (注意 藍色 部分是 match 的) Dynamic Link Compile 時不將 library 加入程式碼,執行程式的時後再將 library 載入程式碼,若有多個程式共用同一個 library,只需載一個 library 進 memory Compile source code $ gcc -c -fPIC file1.c file2.c file3.c -fPIC 表示要編成 position-independent code,這樣不同 process 載入 shared library 時,library 的程式和資料才能放到記憶體不同位置。-fPIC 較通用於不同平台,但產生的 code 較大,而且編譯速度較慢 Create a shared library...

Let's Move On

今天決定要建個部落格 身為資工系的學生, 又那麼愛做筆記 XD 卻到今天才想做這件事似乎有點落漆 還沒明確知道想用來記錄些什麼, 有可能只是與程式相關的東西, 也有可能會很雜 但也很有可能過了一年什麼屁都沒有, 到時候也可以拿出來嘲笑自己一下自我檢討一番 Decide creating the blog today. It seems abnormal for a computer science student to do this so late. After all, I like taking note a lots... Still not sure about what am gonna write here. Maybe all about programming. Maybe it will be really mixed. Nevertheless... very likely that it will still be empty after a year... Then I can open it and piss myself. 迅速 Google 了一下該用哪個平台, 只想找個簡單好用的 外貌先決下 wordpress 和 blogger 脫穎而出, 進一步看了一下覺得並沒有複雜架站的需求所以最後選了 blogger