【问题标题】:Unpacking a class [duplicate]解包一个类[重复]
【发布时间】:2022-02-17 00:38:02
【问题描述】:

我想创建一个类,像字典一样解压它的对象。

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

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

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

【问题讨论】:

  • 据我所知,这不太可能,除非您实际上是在继承 Mapping。否则它将类似于**vars(f)**f.__dict__**f.as_dict()
  • @deceze 我会研究子类映射,谢谢!
  • @deceze 是this 的推荐答案,您推荐什么?"
  • @buran 第二个链接可能,第一个链接在我的问题中。那么**会在后台调用keys函数吗?

标签: python argument-unpacking


【解决方案1】:

正如 cmets 中所指出的,编写一个符合 collections.abc.Mapping 抽象类的子类是可行的方法。要(具体地)子类化这个类,你需要实现__getitem____len____iter__ 以像字典一样表现一致。这意味着__getitem__ 需要一个字符串,__iter__ 返回一个可迭代的字符串,等等。

举个简单的例子,我们将简单地将所有这些委托给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))

【讨论】:

  • 其实这种情况只需要__iter__
  • 您有指定的文档链接吗?我所能找到的只是“**kwargs 需要一个字典”,这显然是一种过度简化,因为上面的代码有效。所以我不确定这条线的确切位置。
  • @Drecker 当我不包括@Silvio 指定的三种方法时,我得到Can't instantiate abstract class _____ with abstract methods <names of methods>
  • 是的,如果我不继承Mapping,那么我会得到TypeError: bar() argument after ** must be a mapping, not FooClass(即使上面的所有代码都相同,只是没有超类)。我认为你必须成为Mapping。但我很想知道 Python 文档中指定的位置。
  • 我的错,显然只实现__iter__ 是不够的(我刚刚测试过)
【解决方案2】:

除了在vars(f)f.__dict__ 上重新调用之外,您还可以使用数据类。

from dataclasses import dataclass, asdict

@dataclass
class FooClass:
    a: int
    b: int

演示:

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

【讨论】:

  • dataclasses 模块中有很多好东西。总有一天我需要从头到尾读完。我不知道asdict 是一个东西。
【解决方案3】:
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

【讨论】:

  • 或者**f.__dict__
猜你喜欢
  • 1970-01-01
  • 2016-09-30
  • 1970-01-01
  • 2015-05-16
  • 2013-12-11
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多