I want to create a class in Python with various attributes and methods, but for it to inherit the functionality of a list, so that I can append objects to the object itself, not any of its attributes. I want to be able to say 'graph[3]
', rather than 'graph.node_list[3]
'. Is there a way to do this?
All you really need to do is provide a __getitem__
In [1]: class Foo:
...: def __init__(self, *args):
...: self.args = args
...: def __getitem__(self, i):
...: return self.args[i]
...:
In [2]: c = Foo(3,4,5)
In [3]: c[2]
Out[3]: 5
In [4]: c[3]
IndexError: tuple index out of range #traceback removed for brevity
In [5]: for i in c: print(i) #look, ma, I can even use a for-loop!
3
4
5
Addendum: There are other methods you probably want to provide, too. __len__
is definitely one of them. There's a rather long list of magic methods, I'd recommend going through them and picking the ones that make sense.
You can just inherit from list
:
class Foo(list):
def __init__(self):
pass
But subclassing builtin types isn't necessarily a good idea.
collections.abc.Sequence
(or since 3.5, typing.Sequence[T]
) is the way I would do it.
You want to add some special methods, such as __getitem__
in the case of lists. Take a look at:
https://docs.python.org/2/reference/datamodel.html#emulating-container-types
Since Python uses duck typing, the primary difference between a list and any other object is the set of methods it exposes. You can easily see the primary attribues (methods and fields) of an object with the dir()
function.
>>> [a for a in dir([]) if callable(getattr([], a))]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
'__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__',
'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index',
'insert', 'pop', 'remove', 'reverse', 'sort']
Obviously there's a lot of methods here, and you probably don't care about most of them. But if your goal was to really replicate the behavior of a list, you'd probably want to implement them. Most of the __...__
methods are defined in Python's data model, if you want to look them up.
From that page:
Mutable sequences should provide methods
append()
,count()
,index()
,extend()
,insert()
,pop()
,remove()
,reverse()
andsort()
, like Python standard list objects. Finally, sequence types should implement addition (meaning concatenation) and multiplication (meaning repetition) by defining the methods__add__()
,__radd__()
,__iadd__()
,__mul__()
,__rmul__()
and__imul__()
described below; they should not define other numerical operators. It is recommended that both mappings and sequences implement the__contains__()
method to allow efficient use of the in operator; for mappings, in should search the mapping’s keys; for sequences, it should search through the values. It is further recommended that both mappings and sequences implement the__iter__()
method to allow efficient iteration through the container; for mappings,__iter__()
should be the same as keys(); for sequences, it should iterate through the values.
The feature you're asking about in particular, index lookups, is provided by __getitem__
. I would suggest also implementing __contains__()
and __iter__()
(and maybe __len__()
), at a minimum.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With