Search code examples
pythonattributessubclasspython-3.3namedtuple

Listing attributes of namedtuple subclass


I have a tiny class that extends a namedtuple, but the __dict__ property of its instances is always returning empty.

Point = namedtuple('Point', 'x y')
p1 = Point(20, 15)
print(p1, p1.__dict__)
# Point(x=20, y=15) OrderedDict([('x', 20), ('y', 15)]) <--- ok

class SubPoint(Point): pass
p2 = SubPoint(20, 15)
print(p2, p2.__dict__)
# SubPoint(x=20, y=15) {} <--- why is it empty?

p2 has the attributes, but its __dict__ is empty. They are listed correctly with dir(), though, which is strange. Note this work correctly when SubPoint extends a vanilla class.

What is happening, and how do I list the attributes in my subclass instance?


Solution

  • To see why __dict__ doesn't work, check the answer by Ashwini Chaudhary. This answer covers the second part of the question (how to list namedtuple attributes).

    To list namedtuple attributes, there are _fields and _asdict:

    >>> import collections as c
    >>> Point = c.namedtuple("Point", ["x", "y"])
    >>> p1 = Point(20, 15)
    >>> print(p1._fields)
    ('x', 'y')
    >>> print(p1._asdict())
    {'x': 20, 'y': 15}
    >>> class SubPoint(Point): pass
    ...
    >>> p2 = SubPoint(20, 15)
    >>> print(p2._fields)
    ('x', 'y')
    >>> print(p2._asdict())
    {'x': 20, 'y': 15}
    

    Note that _fields is defined on the class, so you can also do:

    >>> print(SubPoint._fields)
    ('x', 'y')
    

    Obviously, _asdict needs an instance so it can use the values.

    I used Python 3.9.7 for the examples, I'm not exactly sure when this stuff was added (maybe someone who knows can comment).