【问题标题】:Pythonic way of subclassing a list子类化列表的 Pythonic 方式
【发布时间】:2018-05-22 14:45:06
【问题描述】:

这是我的一般问题空间:

我有一个通过 I2C 的设备的字节/位协议。

我有一个命令“数据库”来完整描述所有位域类型、值和枚举。

我有一个使用数据库的类和一个 i2c 驱动程序/事务处理程序,这样我就可以调用命令并获得响应。

MyProtocol = Protocol('database.xml',I2CDriver())
theStatus = MyProtocol.GET_STATUS()

为 GET_STATUS 命令创建正确的字节流,通过 i2c 发送它并当前以字节数组的形式返回响应。我可以让它在 GET_STATUS() 实现中漂亮地打印响应,但我想将该行为移动到返回对象,而不是在命令中。

我希望我的返回对象“智能”:theStatus 需要包含字节列表/数组以及对其字段定义的引用。

我想让theStatus 像一个列表/字节数组一样工作,所以我可以直接检查字节。我不在乎切片是否不是字节列表或字节数组。一旦它们被切掉,它们就只是字节。

我希望能够打印“theStatus”print(theStatus) 并让它漂亮地打印状态中的所有字段。一旦我确定了一个允许我访问字节和数据库的可行数据结构,我对如何实现这一点感到很自在。

我想用theStatus.FIELDNAMEtheStatus['FIELDNAME']' 之类的字段名称检查theStatus。同样的事情:一旦我有了一个以字节数组和数据库为成员的可行数据结构,我就可以做到这一点。

问题是我不知道导致问题最少的“正确”数据结构。

对完成此任务的最 Pythonic 方式有什么建议吗?我最初的想法是继承list并将字段定义添加为成员,但似乎python根本不喜欢这个想法。

组合似乎是下一个赌注,但让它表现得像一个正确的list 似乎需要大量工作才能让它“正确”。

【问题讨论】:

    标签: python data-structures subclass


    【解决方案1】:

    您真正想要的是实现一个新的sequence type,它可能是可变的。您可以通过实现special methods needed to emulate container types 从头开始​​创建一个,也可以使用合适的collections.abc collection ABC 作为基础。

    后者可能是最容易采用的方法,因为 ABC 为许多方法提供了作为基础版本的实现,这些方法依赖于您必须实现的一些抽象方法。

    例如,(不可变的)Sequence ABC 只需要您提供__getitem____len__ 的实现;基本 ABC 实现提供了其余部分:

    from collections.abc import Sequence
    
    class StatusBytes(Sequence):
        def __init__(self, statusbytes):
            self._bytes = statusbytes
    
        def __getitem__(self, idx_or_name):
            try:
                return self._bytes[idx_or_name]
            except IndexError:
                # assume it is a fieldname
                return FIELDNAMES[idx_or_name]
    
        def __len__(self):
            return len(self._bytes)
    

    如果你真的需要一个完整的列表实现,包括支持丰富的比较(list_a <= list_b)、排序(list_a.sort())、复制[list_a.copy()]和乘法(list_a * 3),那么还有@ 987654325@。此类继承自collections.abc.MutableSequence,并添加了list 在基本序列ABC 上提供的额外功能。如果您需要该额外功能,请坚持使用基本 ABC。

    【讨论】:

    • 我已经这样做了,它工作正常。我实际上出于某种原因选择了UserList(可能会扩展?类似的东西)出于好奇,为什么__init__ 中没有对 super() 的调用?
    • @RussSchultz:在UserList__init__ 中还是在我在示例类中定义的__init__ 中? super().__init__() 并不总是合适的,它要求 MRO 中的所有 __init__ 方法都可以处理相同数量的参数。这使得使用它不那么干燥。 collections.abc 中的 ABC 没有 __init__ 方法,这里不需要使用 super().__init__(),除非你想支持进一步的多继承子类。
    【解决方案2】:

    创建一个继承自collections.UserList 的子类,这正是https://docs.python.org/3/library/collections.html#collections.UserList 的作用

    【讨论】:

      【解决方案3】:

      听起来您正在寻找collections.UserList

      【讨论】:

        猜你喜欢
        • 2019-12-04
        • 2015-04-05
        • 2010-10-29
        • 2010-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多