# 【Python】Python 學習筆記 ## Brief 隨手紀錄撰寫 python 時候的使用概念或語法 ## Context Management 上下文管理 用於程式設計中處理資源管理的技術,例如**操作文件**、**數據庫連接**、**網路連接時**,都需要資源的分配與釋放,那麼上下文管理就會是一個很好的方法,在 Python 中可以透過 `with` 語法達成 * 程式碼可以更簡潔 * 資源管理上更加安全 以下是一個 `Timer` 例子,Context Managment 需要實現兩個方法,分別為 `__enter__` 與 `__exit__`,這兩個函數代表了進入到 `with` 時初始化與離開區塊的時候要執行的動作 ```python import contextlib import time class Timer(contextlib.ContextDecorator): def __init__(self): self.start = 0 self.end = 0 def __enter__(self): self.start = time.time() def __exit__(self, exc_type, exc_val, exc_tb): self.end = time.time() print(self.end - self.start) if __name__ == "__main__": with Timer() as t: time.sleep(2) ``` ## Decorator 修飾器 在 Python 是一種程式設計的模式之一,它可以讓一個 `class` 或 `func` ,在不需要修改程式碼的情況下加上**額外功能**,並可以用語法糖 ( Syntax Candy ) 來讓語法化簡,始其更好的閱讀與表達其意思,例如 `@` ,而 Decorator 可以是一個 `class` 或 `func`,以下是一個在 YOLO 當中所使用的例子 ```python import contextlib class TryExcept(contextlib.ContextDecorator): def __init__(self, msg="", verbose=True): self.msg = msg self.verbose = verbose def __enter__(self): pass def __exit__(self, exc_type, exc_val, exc_tb): if self.verbose and exc_val: print(f"msg : {self.msg}") print(f"exc_type : {exc_type}") print(f"exc_val : {exc_val}") print(f"exc_tb : {exc_tb}") return True @TryExcept(msg="Error occurred in func") def func(): a = 1 b = "b" b = b + 1 if __name__ == "__main__": func() ``` ```python def func_info(func): def warp(*args, **kwargs): # Print function name and arguments print(f"Function name: {func.__name__}") print(f"Args: {args}") # Get docstring if func.__doc__: print(f"Docstring: {func.__doc__}") # Get annotations if func.__annotations__: print(f"Annotations: {func.__annotations__}") # Call the original function result = func(*args, **kwargs) # Print returned value print(f"Returned: {result}") return warp ``` ```python @func_info def multiply(a: int, b: int) -> int: """ Multiply two numbers. """ return a * b ``` ```python if __name__ == "__main__": multiply(5, 3) ``` ## `.py` 檔案資訊 * `__file__` : 為當前這個 `.py` 檔案的名稱 * `__name__` : 就是模組名稱,如果是被import的,就會是模組的名字例如 `exp.py` 就會顯示 `exp`,如果是直接執行,就會是 `__main__` * `__doc__` : 能夠得到當前檔案字串,或者一個類別的字串 ## Dict 字典 Dict 是一種藉由 key-value 的資料結構,key 值是 immutable ( 不可改變的 ),而插入元素是有序的,但是鍵值排列是無序的 * 創建字典 ```python! d = dict(a=1, b=2, c=3) a = ["alan", "alice"] b = [32, 42, 52] d = dict(zip(a, b)) ``` * 更新字典 在 `args` 這行中,由於右側輸入 `kwargs` 優先度比較高,所以執行後本來的 `x` 會被取代掉 ```python kwargs = {"x": 5} override = {"x": 7, "y": 10} args = {**override, **kwargs} # highest priority args on the right kwargs.update(override) ``` ## Enum 列舉能夠提供語意化、型別安全和集中觀禮的常數定義,可以降低程式碼的複雜度,可以讓程式碼避免以硬編碼方式、或者限制鍵值方式,提高程式碼的維護程度 ```python class SubjectType(Enum): TRAIN = auto() VAL = auto() TEST = auto() def to_string(self) -> str: return self.name.lower() @classmethod def from_string(cls, value: str) -> 'SubjectType': return cls[value.upper()] ``` ## Mutable vs Immutable * Mutable obejct 在作為參數傳入函數時,為 Call by reference,在修改時會影響物件本身,所以要仔細確保函數功能是否具備修改物件屬性的 ```python def fun(d): for k, v in d.items(): d[v] = 5 # modify ``` * Immutable objects 在 iterate 時候會不斷創建新的物件,造成開銷 * Multable object : `list`, `set`, `dict` * Immultable object : `int`, `object`, `string`, `tuple` ## Typing 類別提示 在 Python 當中,由於動態型別的特性,也就是執行期間可以更改變數型態,因此在開發過程某變數的型態可能會改變,但對於程式開發者或許不知道其變數變成了甚麼型態,因此類別提示就適合在這樣的情況下使用,用於提示開發者該變數資料型態或者函數輸入資料型態 ```python from typing import Dict, List def fun(d:Dict[str, int], key:int): d[str(key)] = key ``` ### Protocol Protocol 用於提示某個類別是否有實現特定方法,也就是你所設計類別需要實現某個方法才能夠被該函數或類別使用 ```python class DataLoader(Protocol): """Abstract interface: Loads data, returns Dict[str, Any] (DIP, ISP).""" def load(self, path: Path) -> Dict[str, Any]: ... class CSVLoader: """CSV-specific loader (SRP, LSP).""" def load(self, path: Path) -> Dict[str, pd.DataFrame]: if not path.exists(): raise FileNotFoundError(f"CSV file not found: {path}") df = pd.read_csv(path) return {"data": df} class MatLoader: """MAT-specific loader (SRP, LSP, ISP - Separates non-DataFrame formats).""" def load(self, path: Path) -> Dict[str, Any]: if not path.exists(): raise FileNotFoundError(f"MAT file not found: {path}") data = loadmat(path) return {"data": data} ```