# 【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}
```