Let's say i have a class:
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
And a configuration dict:
{
"attr_1": "qack",
"attr_2": 10
}
Note that sometimes, the configuration dict may have different key names, but internally, the program has a way to map a key's value in the dict to the corresponding attribute in the Foo attribute.
{
"attr_1_diff_key_name": "qack",
"2_attr": 10
}
I want to be able to write two functions that map the config dict to Foo and vice versa (aka, being able to convert the config dict into a Foo object and vice versa), like so:
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
}
it's pretty simple enough, but only when the config dict requires all attributes to be included.
In my project, that can't be the case. the config dict may omit a few attributes, where it's given that the program will use default values to replace the missing attributes.
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.
{}
]
My attempts to this problem is as follows:
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
Sure, this may be fine, but the general repetition, both from the conditional expression and the setting of the keys / variables in both functions, isn't something i really want.
Is there a way to make these functions cleaner? (say, without the repetitive parts?)
A common problem with solutions that require stuff like using **kwargs or vars() is that it's a bit too hacky and isn't supported by vscode's renaming feature, which makes refactoring hard in the future. This isn't what i want, but if there is no other way, i can still make do with it.