Reputation: 43
I have a class that accepts a lot of params, and in init method I'm loading them in differently named params. I know it might be a bad design or whatever, but I can't change that right now. I've tried a lot of stuff but nothing really did the thing. Is it possible to do it within dataclasses?
class MyClass:
def __init__(self, vp):
self.viewport = vp
I know that this is not intended behaviour of dataclass but I'm wondering if it's possible to make some workaround.
What I'd like to have is this mapping within dataclass:
@dataclass
class MyClass:
viewport:str = "" # this should get the value from vp argument if possible
so when I call:
mc = MyClass(vp="foo")
print(mc) should return (MyClass(viewport="foo"))
Upvotes: 2
Views: 2841
Reputation: 4407
Would this work?
from dataclasses import dataclass
arg_dict = {'vp':'viewport'}
@dataclass
class RealMyClass():
viewport: str = ''
some_other_field: int = 10
class MyClass(RealMyClass):
def __init__(self, **kwargs):
super().__init__(**{arg_dict[arg]:value for arg, value in kwargs.items()})
print(MyClass(vp='foo'))
MyClass(viewport='foo', some_other_field=10)
Upvotes: 3
Reputation: 744
You could use an InitVar
for the vp
alias.
from dataclasses import dataclass, InitVar
@dataclass
class MyClass:
viewport: str = "" # this should get the value from vp argument if possible
vp: InitVar[str] = None
def __post_init__(self, vp):
if vp:
self.viewport = vp
mc = MyClass(vp="foo")
If you need to define many aliases, you could also write your own decorator that uses Field.metadata
like so:
from dataclasses import dataclass, field, fields
from functools import wraps
def _wrap_init(original_init):
@wraps(original_init)
def __init__(self, *args, **kwargs):
aliases = {}
for field in fields(self):
alias = field.metadata.get("alias")
if alias is not None:
value = kwargs.pop(alias)
aliases[field.name] = value
original_init(self, *args, **kwargs)
for name, value in aliases.items():
setattr(self, name, value)
return __init__
def aliased(cls):
original_init = cls.__init__
cls.__init__ = _wrap_init(original_init)
return cls
@aliased
@dataclass
class MyClass:
viewport: str = field(default="", metadata={"alias": "vp"})
mc = MyClass(vp="foo")
Upvotes: 3
Reputation: 2102
I don't see any context where this would be a good idea, but you can do it in this way:
from dataclasses import dataclass, field, InitVar
@dataclass
class MyClass:
vp: InitVar[str]
viewport: str = field(init=False)
def __post_init__(self,vp):
self.viewport = vp
MyClass(vp='hola')
Which will return:
MyClass(viewport='hola')
Upvotes: 0