listing attributes of namedtuple subclass

  • Last Update :
  • Techknowledgy :

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
   ()

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')

Declaring __slots__ = () in the subclass fixed the problem, but the reason is not clear. As far as I know __slots__ should not change the behavior of code in such subtle ways, so this is not a complete answer.

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):
   __slots__ = ()
p2 = SubPoint(20, 15)
print(p2, p2.__dict__)
# SubPoint(x = 20, y = 15) OrderedDict([('x', 20), ('y', 15)]) < -- - fixed
list(A.__annotations__.keys())

Suggestion : 2

I have a tiny class that extends a anycodings_subclass namedtuple, but the __dict__ property of its anycodings_subclass instances is always returning empty.,What is happening, and how do I list the anycodings_subclass attributes in my subclass instance?,To list namedtuple attributes, there are anycodings_attributes _fields and _asdict:,I used Python 3.9.7 for the examples, anycodings_attributes I'm not exactly sure when this stuff was anycodings_attributes added (maybe someone who knows can anycodings_attributes comment).

I have a tiny class that extends a anycodings_subclass namedtuple, but the __dict__ property of its anycodings_subclass 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 ?

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
   ()

To list namedtuple attributes, there are anycodings_attributes _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 anycodings_attributes class, so you can also do:

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

Declaring __slots__ = () in the subclass anycodings_attributes fixed the problem, but the reason is not anycodings_attributes clear. As far as I know __slots__ should anycodings_attributes not change the behavior of code in such anycodings_attributes subtle ways, so this is not a complete anycodings_attributes answer.

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):
   __slots__ = ()
p2 = SubPoint(20, 15)
print(p2, p2.__dict__)
# SubPoint(x = 20, y = 15) OrderedDict([('x', 20), ('y', 15)]) < -- - fixed
list(A.__annotations__.keys())

Suggestion : 3

last modified July 29, 2022

1._
#!/usr/bin/python

from collections
import namedtuple

City = namedtuple('City', 'name population')

c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)

print(c1)
print(c2)

The example create city namedtuples.

from collections
import namedtuple

First, we import the namedtuple type from the collections module.

City = namedtuple('City', 'name population')

Here we create two namedtuple objects.

$. / basic.py
City(name = 'Bratislava', population = 432000)
City(name = 'Budapest', population = 1759000)
6._
#!/usr/bin/python

from collections
import namedtuple

City = namedtuple('City', 'name population')

c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)

print(c1[0])
print(c1[1])

print(c2.name)
print(c2.population)

Suggestion : 4

namedtuple is a subclass of tuple, which is used to create tuple-like objects with named fields and fixed length.,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.,There are 3 parameters used while creating a namedtuple.,field_names - indicates the attributes associated with the namedtuple

  1. Using typing module
from typing
import NamedTuple

class Address(NamedTuple):
   street: str
door_no: int
country: str
from collections
import namedtuple

Address = namedtuple('Address', ['street', 'door_no', 'country'], defaults = ['Wall Street', '5', 'USA'])

new_address = Address()

print(new_address)

Consider the above Address example. You can access the street field by name or by using 0 as the index value.

print(new_address[0])
# OR
print(new_address.street)
from collections
import namedtuple

Address = namedtuple('Address', ['street', 'door_no', 'country'])

address_list = ['List Avenue', '23', 'USA']
new_address_list = Address._make(address_list)

print(new_address_list)

address_dict = {
   'street': 'Dict Avenue',
   'door_no': '32',
   'country': 'USA'
}
new_address_dict = Address._make(address_dict.values())

print(new_address_dict)
from collections
import namedtuple

Address = namedtuple('Address', ['street', 'door_no', 'country'], defaults = ['Wall Street', '5', 'USA'])

new_address = Address("Penn Street", "56", "USA")

print("Field names:\n")
print(new_address._fields)
print("-" * 10)
print("Field Default Values:\n")
print(new_address._field_defaults)
print("-" * 10)
print("Tuple as dictionary:\n")
print(new_address._asdict())
print("-" * 10)
print("Replace:\n")
print(new_address._replace(street = "Bourbon Street"))

Suggestion : 5

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.),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.,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).

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
   ()

Suggestion : 6

A named tuple is an extension of the regular built-in tuple (namedtuple is a tuple subclass). It provides the same features as the conventional tuple, but also allows you to access fields via attribute lookup using dot notation, that is, using their names instead of only indexes.,On the other hand, namedtuples are just an extension a regular tuple. That means their implementation is based on a faster C code and have a smaller memory footprint.,Now that we understand the motivations behind using namedtuple, it’s time to learn how to convert normal tuples and dictionaries into named tuples. ,No problem, if you pass a dict to the namedtuple factory function, it creates a named tuple class using the dictionary fields.

Suppose that you have a function that converts a string into a color. The color must be represented in a 4-dimensional space, the RGBA.

def convert_string_to_color(desc: str, alpha: float = 0.0):
   if desc == "green":
   return 50, 205, 50, alpha
elif desc == "blue":
   return 0, 0, 255, alpha
else:
   return 0, 0, 0, alpha

Then, we can use it like this:

r, g, b, a = convert_string_to_color(desc = "blue", alpha = 1.0)

Ok, that works, but... we have a couple of problems here. The first one is, there's no way to ensure the order of the returned values. That is, there's nothing stopping another developer to call convert_string_to_color like this:

g, b, r, a = convert_string_to_color(desc = "blue", alpha = 1.0)

Python’s dictionaries are a very versatile data structure. They can serve as an easy and convenient way to store multiple values. However, a dict doesn’t come without shortcomings. Due to its flexibility, dictionaries are very easily abused. As an illustration, let us convert our example to use a dictionary instead of tuple.

def convert_string_to_color(desc: str, alpha: float = 0.0):
   if desc == "green":
   return {
      "r": 50,
      "g": 205,
      "b": 50,
      "alpha": alpha
   }
elif desc == "blue":
   return {
      "r": 0,
      "g": 0,
      "b": 255,
      "alpha": alpha
   }
else:
   return {
      "r": 0,
      "g": 0,
      "b": 0,
      "alpha": alpha
   }

Ok, we now can use it like this, expecting just one value to be returned:

color = convert_string_to_color(desc = "blue", alpha = 1.0)