Pythonic way of subclassing a list

2019-07-11 03:19发布

Here's my general problem space:

I have a byte/bit protocol with a device over I2C.

I've got a "database" of the commands to fully describe all the bitfields types and values and enumerations.

I have a class to consume the database and a i2c driver/transactor so that I can then call commands and get responses.

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

creates the proper byte stream for the GET_STATUS command, sends it over the i2c and returns the response as a byte array currently. I can get it to pretty print the response inside of the GET_STATUS() implementation, but I want to move that behavior to return object, rather than in the command.

I want my return object to be 'smart': theStatus needs to have the list/array of bytes plus a reference to its field definitions.

I want theStatus to act like an list/bytearray, so I can directly inspect the bytes. I don't care if slices are anything other than lists of bytes or bytearray. Once they've been sliced out they're just bytes.

I want 'theStatus' to be able to be printed print(theStatus) and have it pretty print all the fields in the status. I'm comfortable on how to make this happen once I settle on a workable data structure that allows me to access the bytes and the data base.

I want to inspect theStatus by field name with something like theStatus.FIELDNAME or maybe theStatus['FIELDNAME']'. Same thing: once I have a workable data structure that has the byte array and database as members, I can make this happen.

The problem is I don't know the "right" data structure to cause the least amount of problems.

Any suggestions on the most pythonic way to accomplish this? My initial thought was to subclass list and add the field definitions as a member, but it seems like python doesn't like that idea at all.

Composition seems like the next bet, but getting it to act like a proper list seems like that might be a bunch of work to get it 'right'.

3条回答
劫难
2楼-- · 2019-07-11 03:46

It sounds like you're looking for collections.UserList.

查看更多
倾城 Initia
3楼-- · 2019-07-11 03:48

Make a subclass which inherits from collections.UserList, that's exactly what its for https://docs.python.org/3/library/collections.html#collections.UserList

查看更多
戒情不戒烟
4楼-- · 2019-07-11 03:51

What you really want is to implement a new sequence type, one that is perhaps mutable. You can either create one from scratch by implementing the special methods needed to emulate container types, or you can use a suitable collections.abc collection ABC as a base.

The latter is probably the easiest path to take, as the ABCs provide implementations for many of the methods as base versions that rely on a few abstract methods you must implement.

For example, the (immutable) Sequence ABC only requires you to provide implementations for __getitem__ and __len__; the base ABC implementation provides the rest:

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)

If you really need a full list implementation, including support for rich comparisons (list_a <= list_b), sorting (list_a.sort()), copying [list_a.copy()] and multiplication (list_a * 3), then there is also the collections.UserList() class. This class inherits from collections.abc.MutableSequence, and adds the extra functionality that list offers over the base sequence ABCs. If you don't need that extra functionality, stick to base ABCs.

查看更多
登录 后发表回答