Python's Collections Module: namedtuple
Tags: python, codenewbie, collections
Published: 2021-06-18 18:26:54

## Introduction

As it has **tuple** in it's name, one thing is clear that it will add some superpower🦸‍♀️ to the tuples.

`namedtuple` is a  special type of `tuple` that has _named_ indices. Ofcourse, they also have normal integer indices as they are tuples anway.
### Importing namedtuple
```python
from collections import namedtuple
```
## `namedtuple` creation
```python
# Step 1: Define namedtuple
# 'typename'=> used when printing an obj & low-lvl stuff
# 'fieldnames'=> list of names of indices
Student = namedtuple(typename='Student',
                     field_names=['fname', 'lname', 'age']
                     )

# Step 2: Create a namedtuple

# explicitly assigning named indices
s1 = Student(fname="Shan", lname="Patel", age=19)

# named indices are inferred
s2 = Student("Kathan", "Vakharia", 19)

print(s1, s2, sep='\n')

"""OUTPUT
Student(fname='Shan', lname='Patel', age=19)
Student(fname='Kathan', lname='Vakharia', age=19)
"""
```
> 📑 It is important to note that the identifier you use for defining the `namedtuple`(_Student_ here) is the one you have to use while instantiating a `namedtuple`. It has nothing to do with the `typename` argument-It's just a _name_ for your custom tuple sub-class. 

Quoting the python [documentation](https://docs.python.org/3/library/collections.html#collections.namedtuple),

`collections.namedtuple(typename, field_names,...)`
     - Returns a new tuple subclass named _typename_.
We can cross-verify if we want using `issubclass` function.
<pre>
&gt;&gt;&gt; issubclass(Student, tuple)
True
</pre>

```python
# CORRECT WAY
s0 = Student("heet", "vakharia")
print(s0)
"""OUTPUT
blah(fname='heet', lname='vakharia')
""""
```
```python
# INCORRECT way
Student = namedtuple(typename="blah",
                         field_names=["fname", "lname"]
                        )
s1 = blah("kathan", "vakharia")
"""OUTPUT
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'blah' is not defined
"""
```
## Indexing namedtuples
Indexing namedtuple object is very straight-forward. Here's how you do it,
```python
# way1 : using integer indices
# Same like 'plain-tuples'
print("First element of s1: {}"
      .format(s1[0]))

# way 2: using named indices 'NEW'
print("Element of s2 having named index lname: {}"
      .format(s2.lname))
"""OUTPUT
First element of s1: Shan
Element of s2 having named index lname: Vakharia
"""
```
As it is a sub-class of `tuple`, it inherits all the methods and attributs of `tuple`. 
However, there are some interesting methods pertaining to `namedtuple`. Let's see what are those,
### _classmethod_ `somenamedtuple._make(iterable)`
```python
fields = ["John", "Doe", 34]
print(Student._make(fields))

"""OUTPUT
Student(fname='John', lname='Doe', age=34)
"""
```

### `somenamedtuple._asdict()`
Returns a new `dict` which maps field names to their corresponding values,
```python
from collections import namedtuple

Student = namedtuple(typename='Student',
                     field_names=['fname', 'lname', 'age'],
                     )

shan = Student(fname="Shan", lname="Patel", age=19)
kathan = Student("Kathan", "Vakharia", 19)

# namedtuple._asdict() 
print(shan._asdict())
print(kathan._asdict())

"""OUTPUT
{'fname': 'Shan', 'lname': 'Patel', 'age': 19}
{'fname': 'Kathan', 'lname': 'Vakharia', 'age': 19}
"""
```

### `somenamedtuple._replace(**kwargs)`
Returns a new instance of the named tuple replacing specified fields with new values.
```python
kathan = Student("Kathan", "Vakharia", 19)

# a new tuple will be created with changed fname
kathan_v2 = kathan._replace(fname="Karsh")

print(kathan_v2)

# Old kathan is still unchanged
print(kathan)

"""OUTPUT
Student(fname='Karsh', lname='Vakharia', age=19)
Student(fname='Kathan', lname='Vakharia', age=19)
"""
```

And that wraps our discussion on `namedtuple`. I have intentionally left some minor functionalities because they are too trivial :) However, feel free to check out the [documentation](https://docs.python.org/3/library/collections.html#collections.somenamedtuple._fields) for that remaining 5% stuff.