【问题标题】:Implement packing/unpacking in an object在对象中实现打包/解包
【发布时间】:2022-05-18 22:20:11
【问题描述】:

我有一个只包含属性的类,我想打包/解包来处理它。我应该实现什么collections.abc 来获得这种行为?

class Item(object):

    def __init__(self, name, age, gender)
        self.name = name
        self.age = age
        self.gender = gender

a, b, c = Item("Henry", 90, "male")

我想避免使用namedtuple

【问题讨论】:

  • 可以解压任意Iterable,所以需要实现__iter__
  • 这取决于您是否想要__iter__return self - 例如,您可以只使用return iter((self.name, self.age, self.gender))。它必须是iterable,但不一定是一个迭代器
  • 好的,谢谢,我想我明白了。

标签: python python-2.7


【解决方案1】:

您可以解压任何Iterable。这意味着您需要实现__iter__ 方法,并返回一个迭代器。在您的情况下,这可能只是:

def __iter__(self):
    return iter((self.name, self.age, self.gender))

或者,您可以将您的课程设为Iterator,然后将__iter__ 设为return self,并且您需要实现__next__;这是更多的工作,可能不值得付出努力。

欲了解更多信息,请参阅What exactly are Python's iterator, iterable, and iteration protocols?


根据我上面链接的问题,您还可以使用__getitem__ 实现可迭代:

def __getitem__(self, index):
    return (self.name, self.age, self.gender)[index]

【讨论】:

    【解决方案2】:

    解压 Python 3.7+ 数据类的更好选择如下:

    from dataclasses import astuple, dataclass
    
    @dataclass 
    class Item:
        name: str
        age: int
        gender: str
    
        def __iter__(self):
            return iter(astuple(self))
    
    a, b, c = Item("Henry", 90, "male")
    

    【讨论】:

    • object 的子类化是多余的,但在其他方面看起来很合法。
    • 是的——我只是复制了上面的例子。固定。
    • 不幸的是,dataclasses.astuple() 会进行深度解包,这对于嵌套结构来说通常是不可取的——(请参阅stackoverflow.com/a/51802661/1190077)。
    【解决方案3】:

    另一个选项是named tuple

    Item = collections.namedtuple('Item', ['name', 'age', 'gender']) 
    

    所以这是开箱即用的:

    a, b, c = Item("Henry", 90, "male")
    

    如果您使用的是 Python 3.7+,您还可以利用更强大的 dataclasses。但是你需要显式调用astuple:

    @dataclasses.dataclass
    class Item(object):
        name: str
        age: int
        gender: str
    
    a, b, c = dataclasses.astuple(Item("Henry", 90, "male"))
    

    【讨论】:

    • 命名元组也可以用作(匿名)基类,如果您想向该类添加其他方法。 class Item(collections.namedtuple('Item', ['name', 'age', 'gender'])): ...
    • @chepner 很好。我还添加了一个与数据类类似的解决方案,但它们要求您更加明确
    • 这个问题的字面意思是“我想避免使用命名元组”。
    • @wim 叹息。我建议他在此处发布答案,因为stackoverflow.com/q/59568853/1126841 已作为此答案的副本关闭。也许我应该重新打开那个问题,答案可以在那里发布?
    • @wim 我已经添加了带有数据类的第二个解决方案,所以我觉得抱怨它是微不足道的。无论如何,我正在为一个类似的问题提供解决方案,而不是关闭
    【解决方案4】:

    您可以重载 Python 的 __new__() 静态方法,如 official Python documentation 中所述:

    __new__() 主要用于允许不可变类型(如 int、str 或 tuple)的子类自定义实例创建。

    所以你可以通过调整这样的代码来实现类似的行为

    class Item(object):
    
        def __new__(self, name, age, gender):
            return (name, age, gender)
    
    
    if __name__ == "__main__":
        a, b, c = Item("Henry", 90, "male")
        print(a,b,c)
        # output -> Henry 90 male
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-16
      • 1970-01-01
      • 2012-05-21
      相关资源
      最近更新 更多