Changing values of a list of namedtuples

PythonListPython 3.xTuples

Python Problem Overview


I have a list of namedtuples named Books and am trying to increase the price field by 20% which does change the value of Books. I tried to do:

from collections import namedtuple
Book = namedtuple('Book', 'author title genre year price instock')
BSI = [
       Book('Suzane Collins','The Hunger Games', 'Fiction', 2008, 6.96, 20),
       Book('J.K. Rowling', "Harry Potter and the Sorcerer's Stone", 'Fantasy', 1997, 4.78, 12)]
for item in BSI:
    item = item.price*1.10
print(item.price)

But I keep getting :

 Traceback (most recent call last):
 print(item.price)
 AttributeError: 'float' object has no attribute 'price'

I understand that I cannot set the fields in a namedtuple. How do I go about updating price?

I tried to make it into a function:

def restaurant_change_price(rest, newprice):
    rest.price = rest._replace(price = rest.price + newprice)
    return rest.price

print(restaurant_change_price(Restaurant("Taillevent", "French", "343-3434", "Escargots", 24.50), 25))

but I get an error with replace saying:

 rest.price = rest._replace(price = rest.price + newprice)
 AttributeError: can't set attribute

Can someone let me know why this is happening?

Python Solutions


Solution 1 - Python

Named tuples are immutable, so you cannot manipulate them.

Right way of doing it:

If you want something mutable, you can use recordtype.

from recordtype import recordtype

Book = recordtype('Book', 'author title genre year price instock')
books = [
   Book('Suzane Collins','The Hunger Games', 'Fiction', 2008, 6.96, 20),
   Book('J.K. Rowling', "Harry Potter and the Sorcerer's Stone", 'Fantasy', 1997, 4.78, 12)]

for book in books:
    book.price *= 1.1
    print(book.price)

PS: You may need to pip install recordtype if you don't have it installed.

Bad way of doing it:

You may also keep using namedtuple with using the _replace() method.

from collections import namedtuple

Book = namedtuple('Book', 'author title genre year price instock')
books = [
   Book('Suzane Collins','The Hunger Games', 'Fiction', 2008, 6.96, 20),
   Book('J.K. Rowling', "Harry Potter and the Sorcerer's Stone", 'Fantasy', 1997, 4.78, 12)]

for i in range(len(books)):
	books[i] = books[i]._replace(price = books[i].price*1.1)
	print(books[i].price)

Solution 2 - Python

In Python >= 3.7 you can use dataclass decorator with the new variable annotations feature to produce mutable record types:

from dataclasses import dataclass


@dataclass
class Book:
    author: str
    title: str
    genre: str
    year: int
    price: float
    instock: int


BSI = [
    Book("Suzane Collins", "The Hunger Games", "Fiction", 2008, 6.96, 20),
    Book(
        "J.K. Rowling",
        "Harry Potter and the Sorcerer's Stone",
        "Fantasy",
        1997,
        4.78,
        12,
    ),
]

for item in BSI:
    item.price *= 1.10
    print(f"New price for '{item.title}' book is {item.price:,.2f}")

Output:

New price for 'The Hunger Games' book is 7.66
New price for 'Harry Potter and the Sorcerer's Stone' book is 5.26

Solution 3 - Python

This looks like a task for Python's data analysis library, pandas. It's really, really easy to do this sort of thing:

In [6]: import pandas as pd
In [7]: df = pd.DataFrame(BSI, columns=Book._fields)
In [8]: df
Out[8]: 
           author                                  title    genre  year  \
0  Suzane Collins                       The Hunger Games  Fiction  2008   
1    J.K. Rowling  Harry Potter and the Sorcerers Stone  Fantasy  1997   

   price  instock  
0   6.96       20  
1   4.78       12  

In [9]: df['price'] *= 100
In [10]: df
Out[10]: 
           author                                  title    genre  year  \
0  Suzane Collins                       The Hunger Games  Fiction  2008   
1    J.K. Rowling  Harry Potter and the Sorcerer's Stone  Fantasy  1997   

   price  instock  
0    696       20  
1    478       12  

Now isn't that just much, much better than labouring with namedtuples?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLeon SurraoView Question on Stackoverflow
Solution 1 - PythonSaitView Answer on Stackoverflow
Solution 2 - PythonVlad BezdenView Answer on Stackoverflow
Solution 3 - PythonLondonRobView Answer on Stackoverflow