namedtuple – Collections in Python

namedtuple collection in Python is part of the collections module. it provides a simple way to create lightweight object types similar to tuples, but with named fields. Named fields in namedtuple allows for improved code readability and usability compared to traditional tuples.

namedtuple

namedtuple collection in Python, allows us to create classes which are immutable tuples but with named fields. This is a subclass of Python’s built-in tuple. Named fields make the tuple elements more readable because then we can access elements by names rather than indices.

Syntax to create namedtuple object:

namedtuple_class = collections.namedtuple(typename, field_names, rename=False, defaults=(fields), module=None)

)

  • collections is a module in Python. namedtuple class is part of collections module. We need to import collections module to use namedtuple class in our program.
  • namedtuple() is the namedtuple class constructor
  • typename is the name of the class. This name can be used to define values to the named fields.
  • field_names are the space separated field names. We can pass these name as a list as well.
  • rename attribute default value is False. If True, then this attribute will rename the keyword names given as field names.
  • namedtuple_class is the class returned with typename and fields.
  • defaults – These are default values used in case values provided are less than field names. Multiple default values can be provided as tuple. These values can be used for right side field names.
  • module – Default value for module attribute is None. if module is defined, the __module__ attribute of the named tuple is set to that value.

namedtuple Properties

  • It defines the element values for the given field name. Named fields are easier to access, instead of relying on positional indexing.
  • This class object are immutable similar to tuple.
  • Lightweight and memory-efficient compared to normal classes.
  • Number of values provided for object should not be more than the number of field names. Otherwise, TypeError will be raised.
  • field_names should be starting with underscore and should not be using any Python keyword or identifiers. Otherwise ValueError will be raised.

Create namedtuple Class and Object

There are multiple ways, using which we can create namedtuple class object.

  • Using typename and fieldnames
  • Using typename, fieldnames and rename
  • Using typename, fieldnames, rename and default values

Using typename and fieldnames

from collections import namedtuple

# Scenario 1 - create named tuple with default settings
print("create named tuple with default settings")
namedtuple_object = namedtuple('shbytes',['c1','c2','c3']) # field names passed as list
# create object from namedtuple class and assign values to fields
o = namedtuple_object('AWS','Python','DevOps')
print(o)
print(type(o))

# Scenario 2 - create named tuple with field names passed with space separated
print("create named tuple with field names passed with space separated")
shbytes_object = namedtuple('shbytes',"c1 c2 c3") # field names passed with space separated
# create object from namedtuple class and assign values to fields
o = shbytes_object('AWS','Python','DevOps')
print(o)
print(type(o))

# Scenario 3 - create named tuple with field names cannot start with underscore
print("create named tuple with field names cannot start with underscore")
try:
	shbytes = namedtuple('shbytes',['_c1', '_c2']) # field names start with underscore not allowed
except ValueError as err:
	print("error", err)

# Scenario 4 - named tuple - invalid field names
print("named tuple - invalid field names")
try:
	shbytes = namedtuple('shbytes',['c1', 'def', 'c1']) 
except ValueError as err:
	print("error", err)

We are looking for four scenarios while creating the namedtuple class.

  1. Field names are passed as list => namedtuple('shbytes',['c1','c2','c3']) and then we use the class object to assign the values to the fields and create namedtuple_object.
  2. Space separated field names passed as string => namedtuple('shbytes',"c1 c2 c3")
  3. Field name start with underscore will given an ValueError => namedtuple('shbytes',['_c1', '_c2'])
  4. Python keyword identifier is given as field name. In this case ValueError will be raised => namedtuple('shbytes',['c1', 'def', 'c1']). def is a Python identifier used as field name.

Program Output

create named tuple with default settings
shbytes(c1='AWS', c2='Python', c3='DevOps') # namedtuple with field values
<class '__main__.shbytes'>                  # type is the typename given for class

create named tuple with field names passed with space separated
shbytes(c1='AWS', c2='Python', c3='DevOps')  # namedtuple with field values
<class '__main__.shbytes'>

create named tuple with field names cannot start with underscore
error Field names cannot start with an underscore: '_c1'  # Error when field names start with underscore

named tuple - invalid field names
error Type names and field names cannot be a keyword: 'def'

From the Program Output,

  1. In the first scenario, we got the namedtuple class object => shbytes(c1='AWS', c2='Python', c3='DevOps')
  2. In the second scenario also we got similar namedtuple class object => shbytes(c1='AWS', c2='Python', c3='DevOps')
  3. In third scenario, ValueError was raised because field names were started with underscore.
  4. In fourth scenario, ValueError was raised because Python keyword identifier was used as a field name .

Using typename, fieldnames and rename

We cannot create a namedtuple class with the field names start with underscore or with field names which are keyword identifier defined in Python. To create a namedtuple class with these field names, we can use rename attribute as True.

By default, rename attribute is False for namedtuple. With rename = True, invalid field names are renamed with positional values.

from collections import namedtuple

# Scenario 1 - invalid field names are replaced with positional name
print("invalid field names are replaced with positional name")
shbytes_object = namedtuple('shbytes',['_c1', '_c2'], rename=True)
o = shbytes_object('Python','Power BI')
print(o)
print(type(o))

# Scenario 2 - invalid field names are replaced with positional names
print("named tuple - invalid field names are replaced with positional names")
shbytes_object = namedtuple('shbytes',['c1','def','c1'], rename=True)
o = shbytes_object('AWS','Python','Power BI')
print(o)
print(type(o))
  1. In the first case, field name are starting with underscore which is invalid. We are creating a namedtuple class with rename attribute => namedtuple('shbytes',['_c1', '_c2'], rename=True)
  2. In second case, Python keyword identifiers are given as field name and a duplicate field name is used => namedtuple('shbytes',['c1','def','c1'], rename=True). def is a keyword identifier. c1 is used second time.

Program Output

invalid field names are replaced with positional name
shbytes(_0='Python', _1='Power BI')
<class '__main__.shbytes'>

named tuple - invalid field names are replaced with positional names
shbytes(c1='AWS', _1='Python', _2='Power BI')
<class '__main__.shbytes'>
  1. In first case namedtuple class fields was replaced with _0 and _1 => shbytes(_0='Python', _1='Power BI')
  2. In the second case, def field name was replaced with _1 and c1 duplicate field name is replaced with _2 => shbytes(c1='AWS', _1='Python', _2='Power BI')

Using rename and default values

We can use defaults attribute while creating the namedtuple class. defaults attribute provides the default values to the fields of namedtuple.

  • While creating the namedtuple object, if number of field names are more than the number of values provided, then default values can be assigned to those extra fields.
  • Number of values provided for object should not be more than the number of field names. Otherwise, TypeError will be raised.
from collections import namedtuple

# Scenario 1 - named tuple - default value applied to right most parameters
print("named tuple - default value applied to right most parameters")
shbytes_class = namedtuple('shbytes',['c1','c1','c2'], rename=True, defaults=('Python','Power BI'))
o = shbytes_class('AWS')
print(o)
print(type(o))

# Scenario 2 - named tuple - default value is ignored if no parameter left to assign
print("named tuple - default value applied to right most parameters")
shbytes_class = namedtuple('shbytes',['c1','c1','def'], rename=True, defaults=('Python', 'Azure',))
o = shbytes_class('AWS', 'Power BI')
print(o)
print(type(o))

# Scenario 3 - named tuple - Total count of values and default values is less than field names
print("named tuple - Total count of values and default values is less than field names")
try:
	shbytes_class = namedtuple('shbytes', ['c1', 'c1', 'def'], rename=True, defaults=('Python',))
	o = shbytes_class('Power BI')
except TypeError as err:
	print("error", err)

# Scenario 4 - named tuple - more values than field names
print("named tuple - more values than field names")
try:
	shbytes_class = namedtuple('shbytes', ['c1', 'c1', 'def'], rename=True)
	o = shbytes_class('AWS', 'DevOps', 'Python', 'Power BI')
except TypeError as err:
	print("error", err)
  1. In first scenario, we are using defaults=('Python','Power BI') to create namedtuple class. Total field names given are 3. We are passing only 1 value while creating the class object o = shbytes_class('AWS'). Values for 2 extra field names will be taken from default values.
  2. In second scenario, we are again using defaults=(‘Python’, ‘Azure’,) to create namedtuple class. Total field names are 3 and we are passing 2 values while creating the class object o = shbytes_class('AWS', 'Power BI'). Value for 1 extra field name will be taken from default values and 1 default value will remain unused.
  3. In third scenario, we are creating a namedtuple class with 1 default value and class object with 1 value. But field names are 3. Total count of default values and values in class object is 2, which is less than number of field names. This will raise TypeError => missing 1 required positional argument
  4. In third scenario, we are creating a namedtuple with 3 field names and class object with 4 value. Total number of values in class object is more than number of field names. This will also raise TypeError => takes 4 positional arguments but 5 were given

Program Output

named tuple - default value applied to right most parameters
shbytes(c1='AWS', _1='Python', c2='Power BI')
<class '__main__.shbytes'>

named tuple - default value applied to right most parameters
shbytes(c1='AWS', _1='Power BI', _2='Azure')
<class '__main__.shbytes'>

named tuple - Total count of values and default values is less than field names
error shbytes.__new__() missing 1 required positional argument: '_1'

named tuple - more values than field names
error shbytes.__new__() takes 4 positional arguments but 5 were given

Access Elements in namedtuple

There are multiple ways to access elements in a namedtuple object.

  1. Access elements with the field name
  2. Access elements with the index position
  3. Elements unpacked like in a tuple
  4. Using the getattr(namedtuple, variable) method
from collections import namedtuple

# Scenario 1 - namedtuple elements can be accessed with field name
print("namedtuple elements can be accessed with field name")
shbytes_class = namedtuple('shbytes',['c1','c2','c3'])
o = shbytes_class('AWS','Python','DevOps')
print("c1 - ", o.c1)
print("c2 - ", o.c2)
print("c3 - ", o.c3)

# Scenario 2 - namedtuple elements can be accessed with index
print("namedtuple elements can be accessed with index")
shbytes_class = namedtuple('shbytes',['c1','c2','c3'])
o = shbytes_class('AWS','Python','DevOps')
print("c1 - ", o[0])
print("c2 - ", o[1])
print("c3 - ", o[2])

# Scenario 3 - namedtuple elements can be unpacked like tuple
print("namedtuple elements can be unpacked like tuple")
shbytes_class = namedtuple('shbytes',['c1','c2','c3'])
o = shbytes_class('AWS','Python','DevOps')
l, m, n = o
print(l, m, n)

# Scenario 4 - getattr(namedtuple, variable) - to get value for an attribute
print("getattr(namedtuple, variable) - to get value for an attribute")
shbytes_class = namedtuple('shbytes',['c1','c2','c3'])
o = shbytes_class('Python', 'AWS', 'Power BI')
value_c1 = getattr(o, 'c1')
print(value_c1)
print(getattr(o, 'c2'))
print(getattr(o, 'c3'))

In all scenarios, we are creating a namedtuple class with namedtuple('shbytes',['c1','c2','c3']) and object with o = shbytes_class('AWS','Python','DevOps'). Number of field names and values passed are equal. Each field name will assigned value in order from left to right.

  1. In first scenario, we are accessing values based on the field names like o.c1, o.c2, o.c3.
  2. In second scenario, we are accessing values based on the index positions like o[0], o[1], o[2].
  3. In third scenario, we are using unpack of object elements like l, m, n = o. Elements values (from left to right) will be assigned to these unpack variables and then can be used.
  4. In fourth scenario, we are accessing values using getattr method. value_c1 = getattr(o, 'c1') => we are passing object and field name whose value to be accessed.

Program Output

namedtuple elements can be accessed with field name
c1 -  AWS
c2 -  Python
c3 -  DevOps

namedtuple elements can be accessed with index
c1 -  AWS
c2 -  Python
c3 -  DevOps

namedtuple elements can be unpacked like tuple
AWS Python DevOps

getattr(namedtuple, variable) - to get value for an attribute
Python
AWS
Power BI

Method with namedtuple

There are multiple built-in methods applicable with namedtuple class.

  • _make(iterable) – This method used to create another instance of namedtuple
  • _asdict() – This method returns dictionary with values mapped to named parameters
  • _replace(**kwargs) – This method replaces the specified fields with new values and returns a new instance of namedtuple

_make(iterable)

from collections import namedtuple

# Scenario 1 - _make(iterable) - method used on namedtuple object to create another instance
print("_make(iterable) - method used on namedtuple object to create another instance")
Courses = namedtuple('Courses',['c1','c2','c3']) 
course_tuple = Courses('AWS','Python','DevOps')
print(course_tuple)
o = course_tuple._make(course_tuple) # _make used on object
print(o)

# Scenario 2 - _make(iterable) - method used on namedtuple class to create another instance
print("_make(iterable) - method used on namedtuple class to create another instance")
Courses = namedtuple('Courses',['c1','c2','c3']) 
level_tuple = Courses._make(["beginner", "intermediate", "expert"]) # _make used on class
print(level_tuple)

In both scenarios, we are creating a namedtuple class Courses with namedtuple('Courses',['c1','c2','c3']).

  1. In first scenario, we are creating namedtuple object Courses('AWS','Python','DevOps') and then we are using _make() method on this object to create another namedtuple object => o = course_tuple._make(course_tuple)
  2. In second scenario, we are using _make() method on the class to create namedtuple object => level_tuple = Courses._make(["beginner", "intermediate", "expert"])

Program Output

_make(iterable) - method used on namedtuple object to create another instance
Courses(c1='AWS', c2='Python', c3='DevOps')
Courses(c1='AWS', c2='Python', c3='DevOps') # object created using _make() method

_make(iterable) - method used on namedtuple class to create another instance
Courses(c1='beginner', c2='intermediate', c3='expert') # object created using _make() method

_asdict() Method

_asdict() method returns dictionary with values mapped to named parameters.

from collections import namedtuple

# _asdict() - method returns dictionary with values mapped to named parameters
print("_asdict() - method returns dictionary with values mapped to named parameters")
Courses = namedtuple('Courses',['c1','c2','c3']) 
course_tuple = Courses('AWS','Python','DevOps')
print(course_tuple)                  # namedtuple object
print(type(course_tuple))            # type of namedtuple object
course_dict = course_tuple._asdict() # convert to dictionary
print(course_dict)                   # dictionary object
print(type(course_dict))             # type of dictionary object

course_tuple._asdict() to convert the namedtuple object to dictionary key-value pair.

Program Output

_asdict() - method returns dictionary with values mapped to named parameters
Courses(c1='AWS', c2='Python', c3='DevOps')   # namedtuple object
<class '__main__.Courses'>                    # type of namedtuple object
{'c1': 'AWS', 'c2': 'Python', 'c3': 'DevOps'} # dictionary object created using _asdict() method
<class 'dict'>                                # type of dictionary object

_replace(**kwargs) Method

_replace(**kwargs) method replaces the specified fields with new values and returns a new instance of namedtuple.

from collections import namedtuple

# _replace(**kwargs) - method returns a new instance of namedtuple
# replacing the specified fields with new values
print("_replace(**kwargs) - method returns a new instance of namedtuple")

Courses = namedtuple('Courses',['c1','c2','c3']) 
course_tuple = Courses('AWS','Azure','DevOps')
print(course_tuple) # original namedtuple object
replaced_course_tuple = course_tuple._replace(c2='Python',c3='ML') # values replaced using _replace() method
print(replaced_course_tuple) # new object with replaced values

course_tuple._replace(c2='Python',c3='ML') will replace the values of fields c2 and c3 with the new values.

Program Output

_replace(**kwargs) - method returns a new instance of namedtuple
Courses(c1='AWS', c2='Azure', c3='DevOps') # original object elements
Courses(c1='AWS', c2='Python', c3='ML')    # replaced object elements

namedtuple attributes – _fields and _field_defaults

  • _fields is a namedtuple attribute and used to list the field names
  • _field_defaults attribute is used to return the mapping field names to default values
from collections import namedtuple

# _fields - strings listing the field names
print("_fields - strings listing the field names")
Coordinates = namedtuple('Coordinates',['lat','long']) 
c = Coordinates(-34.0667,46.8231)
print(c)          # namedtuple object
print(c._fields)  # Returns the field names as tuple

#_field_defaults - Dictionary mapping field names to default values
print("_field_defaults - Dictionary mapping field names to default values")
shbytes = namedtuple('shbytes', ['c1','c2','c3'], defaults=['Power BI','Python'])
print(shbytes._field_defaults) # Returns fields mapped to default values

Program Output

_fields - strings listing the field names
Coordinates(lat=-34.0667, long=46.8231)
('lat', 'long') # Field names returned using _fields attribute

_field_defaults - Dictionary mapping field names to default values
{'c2': 'Power BI', 'c3': 'Python'} # Field names mapped to default values

Summary

In this article, we learned about namedtuple collection in Python. Following topics were discussed:

Code – Github Repository

All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.

Python Topics


Interview Questions & Answers

Q: How can we create a namedtuple from the dictionary object?

from collections import namedtuple

# convert dictionary to a namedtuple using double-star-operator
print("convert dictionary to a namedtuple using double-star-operator")
Courses = namedtuple('Courses', ['c1', 'c2'])
course_dict = {'c1':'Python', 'c2':'AWS'}
print(course_dict)
print(Courses(**course_dict))

In this program, we have defined a namedtuple class Courses with namedtuple('Courses', ['c1', 'c2']). We have also defined a dictionary {'c1':'Python', 'c2':'AWS'}. Dictionary keys and namedtuple class fields are same. Using Courses(**course_dict) we are converting dictionary elements to namedtuple object.

Dictionary keys and namedtuple field names should be same, otherwise TypeError will be raised.

Q: How does namedtuple compare to a dictionary?

namedtuple are immutable, we cannot perform any modification after object is created. Field names are predefined, improving code readability and predictability. namedtuple are lightweight and memory efficient.

dictionary are mutable, key-value pairs and we can perform update operations after object is created. We can create dictionaries with dynamic keys that are not predefined, this makes them more flexible but sometimes less predictable. Dictionary object consume larger memory compared to namedtuple.

Q: Can we create a nested namedtuple?

Nested namedtuple can be created. We can use one namedtuple as a field inside another namedtuple.

Point = namedtuple('Point', 'x y')
Rectangle = namedtuple('Rectangle', 'top_left bottom_right')

# Create instances of Point
p1 = Point(0, 0)
p2 = Point(10, 10)

# Create an instance of Rectangle using Point
rectangle = Rectangle(top_left=p1, bottom_right=p2)
print(rectangle)  # Output => Rectangle(top_left=Point(x=0, y=0), bottom_right=Point(x=10, y=10))

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *