假設我有一堂課:
class Foo():
"""A class with attr1 and attr2."""
def __init__(self, attr_1: str = "", attr_2: int = 0):
self.attr_1 = attr_1
self.attr_2 = attr_2
和一個配置字典:
{
"attr_1": "qack",
"attr_2": 10
}
請注意,有時,配置 dict 可能具有不同的鍵名,但在內部,程式有一種方法可以將 dict 中的鍵值映射到屬性中的相應Foo屬性。
{
"attr_1_diff_key_name": "qack",
"2_attr": 10
}
我希望能夠撰寫兩個函式,將配置字典映射到Foo反之亦然(也就是能夠將配置字典轉換為Foo物件,反之亦然),如下所示:
def dict_to_foo(dict_config: dict):
"""Returns the Foo equivalent of the dictionary."""
return Foo(
attr_1 = dict_config["attr_1"],
attr_2 = dict_config["attr_2"]
)
def foo_to_dict(foo: Foo):
"""Returns the dictionary equivalent of the Foo object."""
return {
"attr_1": foo.attr_1,
"attr_2": foo.attr_2
}
它非常簡單,但僅當配置字典需要包含所有屬性時。
在我的專案中,情況并非如此。config dict 可能會省略一些屬性,其中假定程式將使用默認值來替換缺少的屬性。
config_dict_examples = [
# Usual, has all attributes
{
"attr_1": "qack",
"attr_2": 10
},
# "attr_2" omitted, it's understood here that the Foo equivalent will have attr_2 set to its default value from the __init__ function, in this case, 0.
{
"attr_1": "qack"
},
# In this case, all attributes are omitted, and thus the Foo equivalent will have both attr_1 and attr_2 set to its default value from the __init__ function, in this case, "" and 0 respectively.
{}
]
我對這個問題的嘗試如下:
def dict_to_foo_attempt_1(dict_config: dict):
"""Attempt 1 of dict_to_foo."""
foo = Foo()
if "attr_1" in dict_config:
foo.attr_1 = dict_config["attr_1"]
if "attr_2" in dict_config:
foo.attr_2 = dict_config["attr_2"]
def foo_to_dict_attempt_1(foo: Foo):
"""Attempt 1 of foo_to_dict."""
dict_config = {}
default_foo = Foo()
if foo.attr_1 != default_foo.attr_1:
dict_config["attr_1"] = foo.attr_1
if foo.attr_2 != default_foo.attr_2:
dict_config["attr_2"] = foo.attr_2
當然,這可能很好,但是從條件運算式和兩個函式中鍵/變數的設定來看,一般的重復并不是我真正想要的。
有沒有辦法讓這些功能更干凈?(比如說,沒有重復的部分?)
**kwargs需要使用或之類的東西的解決方案的一個常見問題vars()是它有點太hacky并且不受vscode的重命名功能的支持,這使得將來難以重構。這不是我想要的,但如果沒有其他辦法,我仍然可以做到。
uj5u.com熱心網友回復:
最干凈的處理方式:
def dict_to_foo(dict_config: dict):
"""Returns the Foo equivalent of the dictionary."""
return Foo(**dict_config)
def foo_to_dict(foo: Foo):
"""Returns the dictionary equivalent of the Foo object."""
return vars(foo).copy()
uj5u.com熱心網友回復:
假設您有一個具有真實屬性名稱的配置字典(您提到有一個映射),您可以迭代字典并setattr僅用于設定必要的屬性。
class Foo():
"""A class with attr1 and attr2."""
def __init__(self, attr_1: str = "default_value", attr_2: int = 0):
self.attr_1 = attr_1
self.attr_2 = attr_2
config = {
"attr_1": "qack",
# "attr_2": 10
}
foo_obj = Foo()
print('Before using config: ',foo_obj.attr_1, foo_obj.attr_2)
for key, value in config.items():
setattr(foo_obj, key, value)
print('After config: ',foo_obj.attr_1, foo_obj.attr_2)
輸出:
Before using config: default_value 0
After config: qack 0
uj5u.com熱心網友回復:
您可以使用字典將引數名稱映射到字典鍵,反之亦然:
FOO_ATTR_TO_KEY = {
'attr_1': 'attr_1_diff_key_name',
}
FOO_KEY_TO_PARAM = {v: k for k, v in FOO_ATTR_TO_KEY.items()}
def dict_to_foo(dict_config: dict):
kwargs = {
FOO_KEY_TO_PARAM.get(key, key): value
for key, value in dict_config.items()
}
return Foo(**kwargs)
def foo_to_dict(foo: Foo):
return {
FOO_ATTR_TO_KEY.get(name, name): value
for name, value in vars(foo).items()
}
uj5u.com熱心網友回復:
有一種更清潔的方法可以做到這一點。
您可以在 python 中更新物件的內部狀態,因為默認情況下它使用字典。
舉個例子
a1 = {"attr_1": "qack", "attr_2": 10}
a2 = {"attr_1": "woof"}
a3 = {"name": "John", "health": -10}
和一堂課
class Foo:
def __init__(self, **attrs):
self.__dict__.update(attrs)
現在我們可以打包字典并將它們傳遞給建構式,如下所示:
f1 = Foo(**a1)
print(f1.__dict__) # {'attr_1': 'qack', 'attr_2': 10}
f2 = Foo(**a2)
print(f2.__dict__) # {'attr_1': 'woof'}
f3 = Foo(**a3)
print(f3.__dict__) # {'name': 'John', 'health': -10}
print(f2.attr_1) # woof
print(f3.name) # John
這為您提供了相同的功能,而您需要撰寫的開銷代碼更少。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/477311.html
