Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing values of a list of namedtuples

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?

like image 877
Leon Surrao Avatar asked Jul 06 '15 18:07

Leon Surrao


People also ask

Can Namedtuples be modified?

Please note, named tuples are immutable, so you cannot manipulate them.

Can Namedtuple be pickled?

@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.

What is an advantage of Namedtuples over dictionaries?

Moreover, as namedtuple instances do not have per-instance dictionaries, they are lightweight and require no more memory than regular tuples. This makes them faster than dictionaries.

What does Namedtuple on a collection type return?

NamedTuple can return the values with keys as OrderedDict type object. To make it OrderedDict, we have to use the _asdict() method.


2 Answers

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 
like image 21
Vlad Bezden Avatar answered Sep 21 '22 09:09

Vlad Bezden


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) 
like image 185
Sait Avatar answered Sep 22 '22 09:09

Sait