0
class Foo:
    def __init__(self, id: int, username: str):
        self.id = id
        self.username = username

dict = {'id':1,'username':'bar', 'extra':0}
x = Foo(**dict)  # Foo.__init__() got an unexpected keyword argument 'extra'

I'm working with some web services that sometimes have extra data in the response that I don't care about. The simplified example above illustrates the problem. Is there a way to use a dictionary to initialize an object, without manually entering each desired key as an argument?

GoldenJoe
  • 7,874
  • 7
  • 53
  • 92
  • If you need to pass variable parameters to any function you should be using keyword arguments – DarkKnight Apr 05 '22 at 06:07
  • 2
    Does this answer your question? [How does one ignore extra arguments passed to a data class?](https://stackoverflow.com/questions/54678337/how-does-one-ignore-extra-arguments-passed-to-a-data-class) – Anshumaan Mishra Apr 05 '22 at 06:08
  • Ah, of course I find it right after I post. Add kwargs with an underscore as the final parameter: `def __init__(self, id: int, username: str, **_):` – GoldenJoe Apr 05 '22 at 06:08

1 Answers1

1

Rather than trying to somehow ignore extraneous arguments, why not take a more flexible approach by accepting all parameters regardless of the order in which they are presented to the class constructor.

Then declare properties (getters & setters) to subsequently access the values.

For example:

class Foo:
    def __init__(self, **kwargs):
        self.kwargs = kwargs
    @property
    def username(self):
        return self.kwargs.get('username')
    @username.setter
    def username(self, value):
        self.kwargs['username'] = value
    @property
    def ident(self):
        return self.kwargs.get('ident')
    @ident.setter
    def ident(self, value):
        self.kwargs['ident'] = value
    def __repr__(self):
        return ', '.join(f'{k}={v}' for k, v in self.kwargs.items())


f = Foo(ident=123)
print(f.ident)
print(f.username)
f.username = 'Lancelot'
print(f.username)
print(f)

Output:

123
None
Lancelot
ident=123, username=Lancelot

The only disadvantage to this that I can think of (there may be others) is that you would not be able to distinguish between values that were not passed to the constructor and those that had a value of None. You'd need to make your getters more elaborate to handle that

DarkKnight
  • 19,739
  • 3
  • 6
  • 22