Cambio de valores de una lista de ejemplares nombrados

Tengo una lista de ejemplares nombrados Books y estoy tratando de boost el campo de price en un 20%, lo que cambia el valor de los Books . Intenté hacer:

 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('JK 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) 

Pero sigo recibiendo:

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

Entiendo que no puedo configurar los campos en una pareja nombrada. ¿Cómo hago para actualizar el price ?

Intenté convertirlo en una función:

 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)) 

pero me sale un error con reemplazar diciendo:

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

¿Alguien puede hacerme saber por qué sucede esto?

Las tuplas nombradas son inmutables , por lo que no puedes manipularlas.

Manera correcta de hacerlo:

Si quieres algo mutable , puedes usar 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('JK Rowling', "Harry Potter and the Sorcerer's Stone", 'Fantasy', 1997, 4.78, 12)] for book in books: book.price *= 1.1 print(book.price) 

PD: Es posible que deba pip install recordtype si no lo tiene instalado.

Mala forma de hacerlo:

También puede seguir usando namedtuple utilizando el método _replace() .

 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('JK 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) 

Esto parece una tarea para la biblioteca de análisis de datos de Python, pandas . Es realmente muy fácil hacer este tipo de cosas:

 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 JK 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 JK Rowling Harry Potter and the Sorcerer's Stone Fantasy 1997 price instock 0 696 20 1 478 12 

¿No es eso mucho, mucho mejor que trabajar con namedtuple s?

En Python> = 3.7 puede usar el decorador de clase de datos con la nueva característica de anotaciones variables para producir tipos de registros mutables:

 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( "JK 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}") 

Salida:

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