Home > Back-end >  __getitem__ for indexing class objects
__getitem__ for indexing class objects

Time:08-27

I am attempting to index the book_list object below to be able to access the values of the attributes "title" and "year" in the Books objects (book1 and book2) :

The code:

class Books:
    def __init__(self, title ='', year = 1):
        self.title = title
        self.year = year

    def __getitem__(self):
        return self.title
        return self.year


class BookList(Books):
    def __init__(self):
        self.book_list = []
          
    def store_book(self, book):
        self.book_list.append(book)

    def __getitem__(self):
        return self.book_list[index]

    def showbook(self):
        for book in self.book_list:
            print(book[0], book[1])

book1 = Books('Title 1', 1000)
book2 = Books('Title 2', 1211)
book_list = BookList()
book_list.store_book(book1)
book_list.store_book(book2)
book_list.showbook()

The current output:

TypeError: __getitem__() takes 1 positional argument but 2 were given

The desired output:

Title 1 1000
Title 2 1211

CodePudding user response:

I tried out your code and made a small tweak. Instead of the following code:

def showbook(self):
    for book in self.book_list:
        print(book[0], book[1])

I believe you just want the following code:

def showbook(self):
    for book in self.book_list:
        print(book.title, book.year)

When I tested the program with that tweak, the following was the output on my terminal.

@Una:~/Python_Programs/Books$ python3 Books.py 
Title 1 1000
Title 2 1211

Test that out and see if it resolves your issue.

Additional notes to respond to your comment.

It appears that when attributes in the initialization function are defined as you have them, they are just that, individual attributes and are not treated like a list that can be indexed. Expanding upon that, I did redo the initialization function as follows:

class Books:
    def __init__(self, title ='', year = 1):
        self.book = []
        self.book.append(title)
        self.book.append(year)

Then, these attributes were a part of a list, and your original block of code worked.

    def showbook(self):
        for book in self.book_list:
            print(book[0], book[1])

The bottom line is that Python appears to be fussy in how attributes are defined within the class.

CodePudding user response:

You need to provide an index to __getitem__ if you want to use it as book[0]

In [1]: class Books:
   ...:     def __init__(self, title ='', year = 1):
   ...:         self.data = (title, year)
   ...: 
   ...:     def __getitem__(self, idx):
   ...:         if idx < 2:
   ...:             return self.data[idx]
   ...:         else:
   ...:             raise IndexError
   ...: 
   ...: 
   ...: class BookList(Books):
   ...:     def __init__(self):
   ...:         self.book_list = []
   ...: 
   ...:     def store_book(self, book):
   ...:         self.book_list.append(book)
   ...: 
   ...:     def __getitem__(self, index):
   ...:         return self.book_list[index]
   ...: 
   ...:     def showbook(self):
   ...:         for book in self.book_list:
   ...:             print(book[0], book[1])
   ...: 
   ...: book1 = Books('Title 1', 1000)
   ...: book2 = Books('Title 2', 1211)
   ...: book_list = BookList()
   ...: book_list.store_book(book1)
   ...: book_list.store_book(book2)
   ...: book_list.showbook()
Title 1 1000
Title 2 1211

If you want to use book['title'] then modify few lines:

In [2]: class Books:
   ...:     def __init__(self, title ='', year = 1):
   ...:         self.data = {'title': title, 'year': year}
   ...: 
   ...:     def __getitem__(self, idx):
   ...:         return self.data[idx]

And then modify the showbook as:

   ...:     def showbook(self):
   ...:         for book in self.book_list:
   ...:             print(book['title'], book['year'])
  • Related