web-dev-qa-db-ja.com

名前付きタプルのリストの値を変更する

Booksという名前のnamedtuplesのリストがあり、priceフィールドを20%増やして、Booksの値を変更しようとしています。私がやろうとしました:

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)

しかし、私は取得し続けます:

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

名前付きタプルにフィールドを設定できないことを理解しています。 priceを更新するにはどうすればよいですか?

私はそれを関数にしようとしました:

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

しかし、私は言って置き換えるとエラーが発生します:

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

誰かがこれが起こっている理由を教えてもらえますか?

26
Leon Surrao

名前付きタプルはimmutableであるため、それらを操作することはできません。

正しい方法:

何かmutableが必要な場合は、 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:インストールしていない場合は、_pip install recordtype_が必要になる場合があります。

悪い方法:

_replace() メソッドを使用して、namedtupleを使用し続けることもできます。

_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)
_
38
Sait

Python> = 3.7では、 dataclass デコレータを新しい変数注釈機能とともに使用して、可変レコードタイプを生成できます。

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

出力:

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

これは、Pythonのデータ分析ライブラリ pandas のタスクのように見えます。この種のことは本当に簡単です。

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  

namedtuplesを使用するよりもはるかに優れていますか?

4
LondonRob