# python self staticmethod classmethod dataclass 理解 ###### tags: `Python`, `self`, `staticmethod`, `classmethod`, `dataclass`, `工廠模式`, `工廠` * 關於 `self` * Python Class 裡的 `self` 會回傳物件本身 (根據物件位址並自動 derefference 為物件)。 * `self` 有點類似 linux kernel 的 macro 中的 [`container_of`](https://hackmd.io/@sysprog/linux-macro-containerof),或 linux kernel 的 macro 中 [`list_entry`](https://github.com/torvalds/linux/blob/master/include/linux/list.h) ```c // list_entry 就是 container_of, // 放在 list.h 中,作為 list API 為了命名統一而重新命名 // 用來獲取「封裝 `struct list_head` 的 // container (也是一個 `struct`) 的『address』」 #define list_entry(ptr, type, member) \ container_of(ptr, type, member) ``` 所以用 linux kernel 的風格來理解的話,==`self` 就是 **The object of object_entry**==。<br>由以下程式碼印出 `self` 訊息,可見 self 就是存於位址 (0x7ffbf95e94c0) 的 calss A 的物件。我所說的 object_entry 就是那段記憶體位址 (0x7ffbf95e94c0)。 ```python class A(): def __init__(self): print(self) print(type(self)) # use class `A` to implement `objA` which is a object of calss `A` objA = A() # stdout: <__main__.A object at 0x7ffbf95e94c0> # stdout: <class '__main__.A'> ``` * 一般情況,class 中所有 method 的第一個參數都會被自動傳入 self * 而 method 的第一個參數 `self` 只是官方慣用命名,其實可以改成任何變數名稱,例如下方範例中,第 5 行命名為 `this`、第 8 行命名為 `object_entry`。<br>有趣的是,`__init__()` 中定義 class 成員是為 `self.value`,但實際上是儲存成 `object_A.value = 0`,因此第 6 行 `set_value()` 可以用 `this.value` 正確存取 `object_A.value`。 * method 會被傳入 the object of object_entry,也就意味只有當 class 實作成 object 之後,才能用 object 呼叫這個 method。因此例外需求就產生了,被加上 `@staticmethod` 的 method 不用建立物件就能透過類別直接呼叫。而加上 `@classmethod` 「**表面上**不用建立物件」可以透過類別直接呼叫。 * 關於 [`staticmethod`](https://docs.python.org/3/library/functions.html#staticmethod) * 有點類似把 class method 當作一個 package api function * 由於 staticmethod 沒有 self 參數,因此無法更動或讀取物件內的任何 member 或 method * 感覺不太實用? 畢竟 Python 實務上通常會把 api 包成一個 package file,而非將各種 api 包進 class。 * 關於 [`classmethod`](https://docs.python.org/3/library/functions.html#classmethod) * ==第一個參數會自動帶入 **The object of class_entry**==,官方預設命名為 `cls` * 實務上,classmethod 要用 cls 生成一個物件,並 return 該物件。一般的 class 是回傳一個初始化物件,而 classmethod 生成物件後,可對該物件作額外操作或配置,然後再回傳。 * 可用於「[工廠模式 Factory Pattern](https://ji3g4zo6qi6.medium.com/python-tips-5d36df9f6ad5)」 ```python= class A(): def __init__(self): self.value = 0 def set_value(this, value): this.value = this.encryption(value) def get_value(object_entry): '''以 linux kernel 風格來說, self 其實就是 object of class_entry ''' return object_entry.value @staticmethod def encryption(value): '''就是一個普通的 function 第一個參數並不會被自動帶入 object of object address, 也不會被帶入 object of class address''' return value+value @classmethod def customize_class(cls, setvalue): '''以 linux kernel 風格來說, cls 其實就是 object of class_entry ''' customize_object = cls() customize_object.set_value(setvalue) return customize_object ``` ```python object_A = A() print(object_A.get_value()) # stdout: 0 object_A.set_value(50) # object_A.value = 50 + 50 print(object_A.get_value()) # stdout: 100 object_A_prime = object_A.customize_class(500) # object_A_prime.value = 500 + 500 print(object_A_prime.get_value()) # stdout: 1000 ``` * 關於 [`dataclass`](https://docs.python.org/3/library/dataclasses.html) * 中文網誌: https://www.maxlist.xyz/2022/04/30/python-dataclasses/ * 帶有 `@dataclass` 標記的 class 會自動獲得 python 常用的 special methods 如:`__init__()` and `__repr__()`,可以使 pyhton code 更精簡 * `@` 在此稱為 `python Decorator`