Search code examples
pythonoopinstance-variables

How to change an instance attribute without changing another instance attribute assigned the same value?


I want to create a Library Management System using Python 3.10.8 and OOPs approach.

I want to make two Instance attributes:

1)listOfBooks :containing the list of books available in the Library's collection(catalogue)

2.)books : containing the list of books in the Library that have not been issued by someone else.

I made a function for borrowing a book(borrowBook) which removes the borrowed book from list stored in books. But somehow list stored in listOfBooks also gets changed which I donot want because I want the displayBooks function to display all books in library collection and not just books which have not been issued.

# Creating Library Class and the 2 attributes
    class Library:
      def __init__(self, listOfBooks):
        self.listBooks = listOfBooks
        self.books = listOfBooks

# Creating function to display books available in library collection
    def displayBooks(self):
        print('Following is the list of books in the library catalogue:')
        for index, book in enumerate(self.listBooks):
            print(index+1, book)

# Creating function to borrow books
    def borrowBook(self, bookName):
        if bookName in self.listBooks:
            if bookName in self.books:
                print(
                    f'{bookName} has been issued to you. Please keep it safe and return it within 30 days!')
       

                self.books.remove(bookName)
            else:
                print(
                    'Sorry the requested book is currently issued to someone else! Please try again later.')
        else:
            print(
                f'{bookName} is currently unavailable in our library catalogue. Sorry for the inconvenience.')
# Creating library object
    centralLibrary = Library(
    ['C', 'C++', 'Algorithms', 'The Jungle Book', 'Heidi'])
# Testing the code
    centralLibrary.displayBooks()
    centralLibrary.borrowBook('The Jungle Book')
    centralLibrary.displayBooks()

How do I change the list inside books and simultaneously keep the list inside listOfBooks as it is?

Also why is the list inside listOfBooks changing anyway?

I am using VS Code(version 1.72.2) as IDE.


Solution

  • Instance variables are for data unique to each instance of a class, while class variables are shared by all instances of a class.

    Make listOfBooks a class variable that is init'd with a method that appends the list of books that you pass to the class when constructing the Library object (i.e. an instance of Library class), which won't update on every instance:

    class Library:
        listOfBooks = []
        def __init__(self, listOfBooks):
            self.books = listOfBooks
            Library.make_class_listOfBooks(listOfBooks) # call method on init
    
        # update class list with the starting list of books;
        @classmethod
        def make_class_listOfBooks(cls, starting_list_of_books):
            for index, book_name in enumerate(starting_list_of_books):
                cls.listOfBooks.append(book_name)
    
        # Creating function to display books available in library collection
        def displayBooks(self):
            print('Following is the list of books in the library catalogue:')
            for index, book in enumerate(Library.listOfBooks):
                print(index + 1, book)
        # Creating function to borrow books
        def borrowBook(self, bookName):
            if bookName in Library.listOfBooks:
                if bookName in self.books:
                    print(f'{bookName} has been issued to you. Please keep it safe and return it within 30 days!')
    
                    self.books.remove(bookName)
                else:
                    print('Sorry the requested book is currently issued to someone else! Please try again later.')
            else:
                print(f'{bookName} is currently unavailable in our library catalogue. Sorry for the inconvenience.')
    

    Running it:

    # Creating library object
    centralLibrary = Library(
      ['C', 'C++', 'Algorithms', 'The Jungle Book', 'Heidi'])
    # Testing the code
    centralLibrary.displayBooks()
    centralLibrary.borrowBook('The Jungle Book')
    centralLibrary.displayBooks()
    centralLibrary.borrowBook('The Jungle Book')
    

    Output:

    Following is the list of books in the library catalogue:
    1 C
    2 C++
    3 Algorithms
    4 The Jungle Book
    5 Heidi
    The Jungle Book has been issued to you. Please keep it safe and return it within 30 days!
    Following is the list of books in the library catalogue:
    1 C
    2 C++
    3 Algorithms
    4 The Jungle Book
    5 Heidi
    Sorry the requested book is currently issued to someone else! Please try again later.
    

    Though your problem is due to assigning two instance attributes to the same object which could be resolved by using a copy (i.e. self.books = listOfBooks.copy()) in the constructor as
    juanpa.arrivillaga had commented. Conceptually, if you wanted to change your Library's collection(catalogue) listOfBooks you'd probably want to change it not for just a single instance but for all instances of the Library class, hence my explanation for using a class variable instead of an instance variable.