Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 547
BoppreH Avatar asked Mar 31 '14 04:03

BoppreH


People also ask

How do I get values from Namedtuple?

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 .

What is a field of a Namedtuple?

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.

What type is a 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.

Is a Namedtuple a class?

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.


1 Answers

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
()
like image 84
Ashwini Chaudhary Avatar answered Oct 14 '22 15:10

Ashwini Chaudhary