开箱 class

Unpacking a class

我想制作一个 class 像字典一样解压它的对象。

例如,使用字典你可以做到这一点

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

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

bar(**foo)

输出3

而且我希望能够做到这一点

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

f = FooClass()
bar(**f)

并让它输出 3

是我能找到的最相关的问题,但它没有解决这个问题,所以我认为这可能是不可能的。


目前我的解决方案是这样的:

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())
def bar(a, b):
   return a + b
  
class FooClass:
    def __init__(self, a, b):
        self.a = a
        self.b = b

f = FooClass(1, 2)

print(bar(*f.__dict__.values()))

# print(bar(**f.__dict__)) # Also works

输出:

3

正如评论中指出的那样,写一个符合 collections.abc.Mapping 摘要 class 的子 class 是可行的方法。要(具体地)subclass this class,您需要实现 __getitem____len____iter__ 以像字典一样一致地运行。所以这意味着 __getitem__ 需要一个字符串,__iter__ returns 一个可迭代的字符串,等等

举个简单的例子,我们将简单地将所有这些委托给 self.__dict__,但在实际代码中,您可能想要做一些更精细的事情。

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))

除了 vars(f)f.__dict__ 上的 reyling,您还可以使用数据类。

from dataclasses import dataclass, asdict

@dataclass
class FooClass:
    a: int
    b: int

演示:

>>> f = FooClass(1, 2)
>>> asdict(f)
{'a': 1, 'b': 2}