示例代碼:
@classmethoddef from_mongo(cls: Type[T], data: dict) -> T:"""Convert "_id" (str object) into "id" (UUID object)."""if not data:raise ValueError("Data is empty.")id = data.pop("_id")return cls(**dict(data, id=id))
這段代碼分成兩部分來理解:
-
dict(data, id=id) 部分:
- 作用:
這里調用了 Python 內置的dict()
構造函數,它接受一個已有的字典(這里是data
)以及額外的關鍵字參數(這里是id=id
)。 - 效果:
它會創建一個新的字典,這個字典包含data
中的所有鍵值對,同時如果data
中已經有id
鍵,那么它會被新傳入的id
覆蓋;如果沒有,則會新增一個id
鍵。 - 舉例說明:
假設:
那么data = {"name": "Alice", "age": 30} id_value = "123e4567-e89b-12d3-a456-426614174000"
dict(data, id=id_value)
生成的新字典就是:
如果{"name": "Alice","age": 30,"id": "123e4567-e89b-12d3-a456-426614174000" }
data
原來已經有一個id
鍵,例如:
則執行data = {"name": "Alice", "age": 30, "id": "old-id"}
dict(data, id=id_value)
后,新字典中"id"
的值將變為"123e4567-e89b-12d3-a456-426614174000"
,覆蓋原來的"old-id"
。
- 作用:
-
cls(…) 部分:**
- 作用:
這里的cls
通常代表當前類(比如在一個類方法中用cls
來引用類本身),**
是解包運算符。 - 效果:
當你寫cls(**some_dict)
時,相當于把字典some_dict
中的每個鍵值對都作為關鍵字參數傳給類的構造方法。 - 舉例說明:
假設我們有一個類User
定義如下:
如果有字典:class User:def __init__(self, name, age, id):self.name = nameself.age = ageself.id = id
那么調用user_data = {"name": "Alice","age": 30,"id": "123e4567-e89b-12d3-a456-426614174000" }
User(**user_data)
就等價于:User(name="Alice", age=30, id="123e4567-e89b-12d3-a456-426614174000")
- 作用:
綜合解釋 cls(**dict(data, id=id))
:
- 首先,
dict(data, id=id)
會生成一個新的字典,這個字典包含了data
中所有的鍵值對,并確保鍵"id"
的值被更新為變量id
的值。 - 然后,
cls(**dict(...))
會調用類cls
的構造方法,把這個字典中的鍵值對逐個傳入作為命名參數,從而創建并返回一個新的類實例。
通俗舉例:
假設有如下情況:
data = {"name": "Bob", "age": 25}
id = "uuid-0001"
- 類
Person
定義為:class Person:def __init__(self, name, age, id):self.name = nameself.age = ageself.id = iddef __repr__(self):return f"Person(name={self.name}, age={self.age}, id={self.id})"
那么,執行 Person(**dict(data, id=id))
的過程如下:
- 生成新字典:
dict(data, id=id)
得到:{"name": "Bob", "age": 25, "id": "uuid-0001"}
- 調用構造函數:
Person(**{"name": "Bob", "age": 25, "id": "uuid-0001"})
就相當于執行:Person(name="Bob", age=25, id="uuid-0001")
- 創建實例:
得到一個Person
對象,其屬性分別為name="Bob"
,age=25
,id="uuid-0001"
。
這樣寫的好處是可以靈活地從一個字典生成實例,同時確保某些關鍵字段(如 id
)被正確設置或覆蓋。