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'.
It sounds like you're looking for collections.UserList.
Make a subclass which inherits from
collections.UserList
, that's exactly what its for https://docs.python.org/3/library/collections.html#collections.UserListWhat 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: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 thecollections.UserList()
class. This class inherits fromcollections.abc.MutableSequence
, and adds the extra functionality thatlist
offers over the base sequence ABCs. If you don't need that extra functionality, stick to base ABCs.