If you want to learn more about
collections.namedtuple, then check out Write Pythonic and Clean Code With namedtuple.
Partially Emulating collections.namedtuple
If you want to learn more about
collections.namedtuple. As a final example of how to take advantage of
.__new__() in your code, you can push your Python skills and write a factory function that partially emulates
namedtuple() function allows you to create subclasses of
tuple with the additional feature of having named fields for accessing the items in the tuple.
Next, you’ll see code that implements a
named_tuple_factory() function that partially emulates this functionality by overriding the
.__new__() method of a nested class called
First, you import
itemgetter from the
operators module. This function allows you to retrieve items using their index in the containing sequence.
named_tuple_factory() is defined. This function takes a first argument called
type_name, which will hold the name of the tuple subclass that you want to create.
*fields argument allows you to pass an undefined number of field names as strings. Here, you define a local variable to hold the number of named fields provided by the user. Here, you define a nested class called
NamedTuple, which inherits from the built-in
This provides a
.__slots__ class attribute. This attribute defines a tuple for holding instance attributes. This tuple saves memory by acting as a substitute for the instance’s dictionary, which would otherwise play a similar role.
Next you implement
cls as its first argument. This implementation also takes the
*args argument to accept an undefined number of field values.
Then you define a conditional statement that checks if the number of items to store in the final tuple differs from the number of named fields. If that’s the case, then the conditional raises a
TypeError with an error message.
This sets the
.__name__ attribute the current class to the value provided by
type_name. These lines define a
for loop that turns every name field into a property that uses
itemgetter() to return the item at the target
The loop uses the built-in
setattr() function to perform this action. Note that the built-in
enumerate() function provides the appropriate
This line returns a new instance of the current class by calling
super().__new__() as usual. These lines define a
.__repr__() special method for the tuple subclass.
Finally, this line returns the newly created
To try the
named_tuple_factory() out, start an interactive session in the directory containing the
named_tuple.py file and run the following code.
First, create a new
Point class by calling
named_tuple_factory(). The first argument in this call represents the name that the resulting class object will use.
The second and third arguments are the named fields available in the resulting class. Then you create a
Point object by calling the class constructor with the appropriate values for the
03:35 To access the value of each named field, you can use dot notation. You can also use indices to retrieve the values because your class is a tuple subclass.
Because tuples are an immutable data type in Python, you can’t assign new values to the point’s coordinates in place. If you try to do that, you get an
dir() with your
point instance as an argument reveals that your object inherits all of the attributes and methods that regular tuples have in Python.
04:13 Now that you’ve covered all the content in this course, in the next section, you’ll take a look back at what you’ve learned.
@Michal B While the common standard is to use
**kwargs, it’s mainly for generic arguments. In this case, it’s more descriptive to use the term
*fields since this function is specifically for creating a named tuple. So, yes, sometimes it makes more sense to use other argument names.
Become a Member to join the conversation.
Michal B on March 13, 2023
In 1:02, is the
I am aware that args and kwargs are arbitrary names, however if it’s the standard, then maybe we should be sticking to it? Unless ‘fields’ is something else?