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?
Python's namedtuple() is a factory function available in collections . It allows you to create tuple subclasses with named fields. You can access the values in a given named tuple using the dot notation and the field names, like in obj. attr .
Different ways of access field names of a namedtuple As namedtuples are a subclass of tuples, the fields can be accessed via the index or by the name of the field. The index value of a field is tied to the order during the declaration of the namedtuple.
Named tuple container datatype is an alternative to the built-in tuple . This extension type enhances standard tuples so that their elements can be accessed by both their attribute name and the positional index. Named tuples are available in Python's standard library collections module under the namedtuple utility.
NamedTuple: The NamedTuple is a class that contains the data like a dictionary format stored under the 'collections' module. It stored the data in a key-value format where each key having mapped to more values. So, we access those data using a specific key or can use the indexes.
The problem is that __slots__
is only limited to a class it is defined in, so base classes will always have their own __dict__
attribute unless you define __slots__
there too. (And also note that the __dict__
attribute of namedtuple
is not a normal dict but a @property.)
From docs:
The action of a
__slots__
declaration is limited to the class where it is defined. As a result, subclasses will have a__dict__
unless they also define__slots__
(which must only contain names of any additional slots).
So, when you defined __slots__
in the subclass then it failed to look for an attribute __dict__
in that class, so moved on to base class where it found the __dict__
attribute.
A simple demo:
class A:
__slots__= ('a', 'b')
@property
def __dict__(self):
print ('inside A')
return self.__slots__
class B(A):
pass
print(B().__dict__)
print ('-'*20)
class B(A):
__slots__ = ()
print(B().__dict__)
output:
{}
--------------------
inside A
()
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