文章

Python 的 typing.Protocol 怎麼使用?

Python 3.8 之後 typing 模組 新增 1 個 typing.Protocol 的 class 可以使用,這個 class 很適合用來給一些有實作特定方法的 class 們做 type annotation 。

舉個常見的交通工具作為例子,假設我們有 1 個函數接受任何有實作 move() 方法的 instance:

def move(x):
    x.move()

這時候可以用 typing.Protocol 將參數 x 加上 1 個 type hint, 讓彼此知道此處不管型別,只管是否有實作 move() 方法:

from typing import Protocol

class Movable(Protocol):
    def move(self):
        ...

def move(x: Movable):
    x.move()

加上 typing.Protocol 是否看起來清晰很多?

Posted on  Sep 25, 2023  in  Python 程式設計 - 中階  by  Amo Chen  ‐ 4 min read

Python contextvars 模組教學

大家都知道執行緒(Threads)之間會共用 Process 的記憶體,這種共用的情況有可能造成 Race Condition, 使得程式出現不可預期的行為或錯誤,所幸這個問題可以透過 threadling.local 解決。

而 Python 3.4 之後推出 asyncio 模組,使得 Python 具備執行非同步 I/O (asynchronous I/O) 的能力,開發者可以同時結合 multiprocessing , threading 以及 asyncio 將 Python 效能提升至全新檔次,但是當結合 threading 以及 asyncio 時,可能會遭遇一個問題, 多個協程(coroutines)可能會在同 1 個執行緒中執行,因此多個 coroutines 也可能有互相影響的情況!所以有了 contextvars 模組,用以解決 coroutines 互相干擾的情況,將每個 coroutine 以 Context 切開,避免互相干擾!

Thread-local variables are insufficient for asynchronous tasks that execute concurrently in the same OS thread. Any context manager that saves and restores a context value using threading.local() will have its context values bleed to other code unexpectedly when used in async/await code.

Posted on  Sep 21, 2023  in  Python 程式設計 - 高階  by  Amo Chen  ‐ 4 min read

Python 套件推薦 - rustimport 給你的 Python 一對翅膀

不可否認 Python 以其優異的生態系與社群資源為開發帶來速度優勢。

不過每個應用都有效率極限, Python 當然也不例外,而且 Python 天生比起 JavaScript, Java 等語言更容易遇到效能瓶頸,這時候通常有 3 種選擇:

  1. 改用效率較好的寫法或套件
  2. 部分功能/元件改用別的語言實作
  3. 全部用別的語言實作

選項 1 是最簡單的,只要能夠找到更快的寫法或者更好的套件,就能夠緩解問題,再撐一陣子;選項 3 則是最困難的,要有足夠的時間以及負責人的支持之下,才有可能進行,畢竟所有的功能都必須改寫之外,測試也是需要全部重新來過,更何況通常公司專案都有時程壓力,選項 3 通常都是難以說服高層的選項;至於選項 2 則是折衷選項,建議選項 1 已經無法解決問題時採用,目前很多 Python 套件為了效率也都會採用選項 2 的做法,例如 orjson 就是以 Rust 語言實作的 JSON parser 。

目前 Python 與 Rust 的介接主要靠 PyO3 , 不過步驟稍微複雜一些,本文將介紹如何透過 rustimport 套件,極度簡化介接 Python 與 Rust 的方法,讓開發 Python 擴充套件可以更快樂、簡便!

Posted on  Sep 18, 2023  in  Python 模組/套件推薦 , Python 程式設計 - 高階  by  Amo Chen  ‐ 4 min read

教練,我想做產品之 Anikit 的起源

勇敢,是帶著害怕前進 # 每次跟人聊天都鼓勵別人去勇敢追夢、大膽行動,不過自己卻好像也從來沒做些什麼,說穿了也是一個不想辛苦,只想乘涼不勞而獲的

Posted on  Sep 6, 2023  by  Amo Chen  ‐ 3 min read

Python - 用範例學 weakref 模組

Python 是 1 個有垃圾回收機制(garbage collection, 或簡稱 GC)的程式語言,簡而言之是一種自動的記憶體管理機制,當某些記憶體空間沒有任何程式用到時,就會被回收,然後釋放這些記憶體空間,避免記憶體越用越少,最後導致程式錯誤、無法執行等問題。

GC 機制是為了減少開發者的負擔,例如 C 語言就需要手動釋放記憶體空間(詳細請參閱 free() 函式),所以忘記釋放記憶體空間造成記憶體洩漏(memory leak)的問題屢見不鮮,但如果交給 GC 的話,就可以讓開發者不太需要考慮記憶體管理的問題,增加開發的效率也降低犯錯的機率。

而 Python 的垃圾回收機制,是使用一種稱為 reference counting 的技術實作。

Posted on  Sep 6, 2023  by  Amo Chen  ‐ 7 min read

Python threading.local() 解說

我們都知道多個執行緒(thread)之間會共用 Process 的記憶體,那你覺得以下範例程式的執行結果會是什麼呢?這是 2 個執行緒分別做 +1 與 -1 運算各 100,000 次的 Python 程式:

import threading


def count(thread_name, step=1):
    global v
    for i in range(0, 100000):
        v += 1 * step
    print(f'{thread_name} -> ', v, flush=True)


v = 0
t1 = threading.Thread(target=count, args=('t1', 1, ))
t2 = threading.Thread(target=count, args=('t2', -1, ))
t1.start()
t2.start()
t1.join()
t2.join()

這段範例程式的執行結果,就跟本文要解說的 threading.local() 有關。

Posted on  Sep 4, 2023  in  Python 程式設計 - 高階  by  Amo Chen  ‐ 3 min read

Python 好用套件 - docxtpl 把 docx 文件檔變樣板(template)

遙想以前在公家機關工作時,不管什麼部門都很喜歡設計各式各樣的 docx 檔,例如用 docx 檔做例行性的報表,每天填完之後寄去給上一層的部門進行彙整,這些東西做久了就會覺得無趣,後來我就用 VBA 把 docx 檔變成樣板,裡面有著一堆可以填充文字的 placeholder, 只要執行 VBA 就可以自動產生新的 docx 檔,把分分鐘的事情變成秒秒鐘。

不過 VBA 畢竟還是沒 Python 可愛宜人,不要再用 VBA 了,能夠用 Python 解決的,都要用 Python 解!卍解!

直接交給 Python 套件 docxtpl 吧!

Posted on  Sep 3, 2023  in  Python 模組/套件推薦  by  Amo Chen  ‐ 1 min read