Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unpacking a class [duplicate]

I'd like to make a class that unpacks it's objects like a dictionary.

For example, with a dictionary you can do this

foo = {
  "a" : 1
  "b" : 2
}

def bar(a,b):
   return a + b

bar(**foo)

outputs 3

And I'd like to be able to do this

class FooClass:
    def __init__(self):
        self.a = a
        self.b = b

f = FooClass()
bar(**f)

and have it output 3

This is the most related question I could find but it doesn't address this so I'm thinking it might not be possible.


Currently what my solution would be this:

class FooClass:
    def __init__(self):
        self.a = a
        self.b = b

    def to_dict(self):
        return {
          "a" : self.a,
          "b" : self.b
        }
f = FooClass()
bar(**f.to_dict())
like image 945
financial_physician Avatar asked Nov 01 '25 21:11

financial_physician


1 Answers

As pointed out in the comments, writing a conformant subclass of the collections.abc.Mapping abstract class is the way to go. To (concretely) subclass this class, you need to implement __getitem__, __len__, and __iter__ to behave consistently like a dictionary would. So that means __getitem__ expects a string, __iter__ returns an iterable of strings, etc.

For a simple example, we'll simply delegate all of these to self.__dict__, but in real code you'd likely want to do something more refined.

from collections.abc import Mapping

class FooClass(Mapping):

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __getitem__(self, x):
        return self.__dict__[x]

    def __iter__(self):
        return iter(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

def bar(a, b):
    return a + b

foo = FooClass(40, 2)
print(bar(**foo))
like image 124
Silvio Mayolo Avatar answered Nov 03 '25 11:11

Silvio Mayolo