Library Member class, can't figure out where I'm going wrong - python

I am trying to complete a series of class definition tasks and can't seem to get past this one. It is part of a 3 part series; the first part asks you to model a library book, which I could complete easily.
The next part is asking to create a Member class to model a library member and include a borrow_book() and a return_book() method, and to get the member's list of all loan books to print out in alphabetical order.
I cannot understand which part I am going wrong on. Could someone possibly point me in the right direction? I have included my code so far below.
class Book(object):
def __init__(self, title, author, copies=1, loan=0):
self.title = title
self.author = author
self.copies = copies
self.loan = loan
def checkbook(self, title):
for book in self.title:
if book.title in self.title:
return book
else:
print("Sorry, Not Available.")
def borrow_book(self):
abc = self.checkbook(title)
print(abc)
self.loan += 1
self.copies -= 1
def return_book(self):
self.loan -= 1
def __str__(self):
r = []
r.append('Title: {}'.format(self.title))
r.append('Author: {}'.format(self.author))
r.append('Copies: {}'.format(self.copies))
r.append('On loan: {}'.format(self.loan))
return '\n'.join(r)
def sort_books(b):
return b.title
class Member(object):
def __init__(self, mid, name, loans=0):
self.mid = mid
self.name = name
self.loans = loans
self.d = {}
def __str__(self, mid, name, loans=0):
r = []
r.append('ID: {}'.format(self.mid))
r.append('Name: {}'.format(self.name))
r.append('Loans: {}'.format(self.loans))
l = ['{}'.format(b) for b in sorted(self.d.values(), key=sort_books)]
return '\n'.join(r)
return '\n'.join(l)

Related

Using For loop with a class object

I am trying to iterate through a class object that contains 2 class objects within it and find a matching attribute using a for loop, the attribute here is "title" that has the value = "hello there", so asking for an input title then try to match it with a title within the 2 class objects , when i enter the correct title, i still get the error that says "Error: Please enter a valid book title" ..
import random
books = []
def random_title():
title = 'hello there'
return title
class Books:
def __init__(self, title =''):
self.title = title
def set_title(self, title = '' ):
self.title = random_title()
def get_title(self):
return self.title
def __getitem__(self, title):
return self.title
class BookList(Books):
def __init__(self):
self.book_list = []
def store_book(self, book):
self.book_list.append(book)
def search_book(self):
search_method = input()
while True:
if search_method not in ['1']:
search_method = input()
else:
search_method = int(search_method)
if search_method == 1:
book_title = input().title()
while True:
for item in self.book_list:
if book_title != item.title or book_title != "Back":
book_title = input('Error: Please enter a valid book title or "back" to go back to the main menu: ').title()
else:
if book_title == 'Back':
main()
else:
if book_title == item.title:
print(item)
def __getitem__(self, index):
return self.book_list[index]
def main():
book1 = Books()
book1.set_title()
book2 = Books()
book2.set_title()
book_list = BookList()
book_list.store_book(book1)
book_list.store_book(book2)
book_list.search_book()
main()
This code does what you were trying to do. I suggest you compare this to your own code to see where you went awry.
books = []
class Books:
def __init__(self, title =''):
self.title = title
def set_title(self, title = '' ):
self.title = title
def get_title(self):
return self.title
class BookList(Books):
def __init__(self):
self.book_list = []
def store_book(self, book):
self.book_list.append(book)
def search_book(self):
while True:
search_method = int(input('Method? '))
if search_method in [1]:
break
print("try again")
if search_method == 1:
while True:
book_title = input('Title? ')
if book_title == "back":
return False
for item in self.book_list:
if book_title == item.title:
print(item)
break
else:
print('Error: Please enter a valid book title or "back" to go back to the main menu.')
def __getitem__(self, index):
return self.book_list[index]
def main():
book1 = Books('one')
book2 = Books('two')
book_list = BookList()
book_list.store_book(book1)
book_list.store_book(book2)
book_list.search_book()
main()
There are some more significant design problems here. The BookList class should not be doing any I/O. It is a utility class. The mainline code should ask for the search method and the book title, and then call methods in the BookList to do the search and return the found result. Let the main code do any I/O that is needed.

How to add new variables into objects to use in classes

I have the code:
import timedelta
class Tune:
def __init__(self, title, artist, duration):
self.title = title
self.artist = artist
self.duration = duration
class Play:
def __init__(self):
self.tracks = []
def add(self, song):
self.tracks.append(song)
def delete(self, number):
del (self.song(number))
def look(self, song):
for song in self.tracks:
print(f"{song.artist} - {song.title}")
def duration(self):
s=0
for y in range(0,len(self.song)):
s = s + self.song[y]
print(int(datetime.timedelta(seconds=s)))
n = int(input("Enter the number of tracks to add"))
playlist = Play()
for i in range(n):
title, artist, duration = input("Enter the title, artist, and duration of a track").split(',')
song = Tune(title, artist, duration)
playlist.add(song)
playlist.look()
playlist.duration
playlist.delete (2)
for every input, i have to make it an object pertaining to its class and add it to the list, with the option of removing it when it is called. When song.look is called, it is supposed to print out the title and artist in the list. For example, if the input is:
2
Artic Monkeys,R U Mine?,324
Artic Monkeys,Do I wanna know?,253
when the program is executed it should output:
1 - Artic Monkeys - R U Mine?
2 - Artic Monkeys - Do I wanna know?
when duration is executed:
00:09:62
when the delete is executed:
1 - Artic Monkeys - R U Mine?
and if song.duration is called, it should output the total duration in the format of hours:minutes:seconds. I think the add and look is correct, my only problem is how do i make it so that it can have track number and how can i use it to remove said tracks? and is my program for duration correct?
Edit: I can only change the def for the class Play, I cant change the contents of Tune
import time
class Tune:
def __init__(self, title, artist, duration):
self.title = title
self.artist = artist
self.duration = duration
class Play:
def __init__(self):
self.tracks = []
def add(self, song):
self.tracks.append(song)
def delete(self, number):
self.tracks.pop(number-1)
def look(self):
for i in range(len(self.tracks)):
print(f"{i+1} -{self.tracks[i].artist} - {self.tracks[i].title}")
def duration(self):
s = 0
for y in range(len(self.tracks)):
s += int(self.tracks[y].duration)
print(time.strftime('%H:%M:%S', time.gmtime(s)))
n = int(input("Enter the number of tracks to add"))
playlist = Play()
for i in range(n):
title, artist, duration = input("Enter the title, artist, and duration of a track").split(',')
song = Tune(title, artist, duration)
playlist.add(song)
playlist.look()
playlist.duration()
print("After Deleting 2nd....")
playlist.delete (2)
playlist.look()
print("After Deleting 2nd....")
playlist.delete (2)
playlist.look()

overload the > operator (__gt__)

I want my Book class to overload the > operator __gt__. So, I can use it in my BookCollection to find the right order.
I used > in InsertBook(). But it is not working! How do I fix it? I want it to be ordered by
the Book’s author (alphabetical / lexicographical order)
the Book’s year of publication
the Book’s title (alphabetical / lexicographical order).
This is my current code for the class Book.py:
class Book:
def __init__(self, title='', author='',year=None):
self.title = title
self.author = author
self.year = year
def setTitle(self, title):
self.title = title
def setAuthor(self, author):
self.author = author
def setYear(self, year):
self.year = year
def getTitle(self):
return self.title
def getAuthor(self):
return self.author
def getYear(self):
return self.year
def __gt__(self,item):
if (0,1,0) > (0,0,0):
return self.author > item.author
else:
return False
if (1,0,0) > (0,0,0):
return self.title > item.title
else:
return False
if (0,0,1) > (0,0,0):
return self.year > item.year
else:
return False
def getBookDetails(self):
return "Title: {}, Author: {}, Year: {}".format(self.title, self.author, self.year)
class BookCollection():
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def insertBook(self, book):
current = self.head
previous = None
stop = False
while current != None and not stop:
if current.getData() > book:
stop = True
else:
previous = current
current = current.getNext()
temp = BookCollectionNode(book)
if previous == None:
temp.setNext(self.head)
self.head = temp
else:
temp.setNext(current)
previous.setNext(temp)
def getNumberOfBooks(self):
temp = self.head
count = 0
while temp != None:
count = count + 1
temp = temp.getNext()
return count
def getAllBooksInCollection(self):
current = self.head
output = ""
while current != None:
output += str(current.getData()) + " "
current = current.getNext()
output = output[:len(output)-1] + "\n"
return output
def getBooksByAuthor(self,item):
current = self.head
found = False
stop = False
while current != None and not found and not stop:
if current.getData() == item:
found = True
else:
if current.getData() > item:
stop = True
else:
current = current.getNext()
return found
I used > in InsertBook(). But it is not working! How do I fix it? I want it to be ordered by
Your overload of the method makes no sense, why are you comparing completely static tuple values? That's always going to do the same thing, so your entire override is really just return self.author > item.author
Overriding __gt__ alone is a bad idea: you really need to override them all or you'll get incoherent result. The functools.total_ordering class decorator allows overriding just __eq__ and one ordering operator, you probably want to use that.
I want it to be ordered by
the Book’s author (alphabetical / lexicographical order)
the Book’s year of publication
the Book’s title (alphabetical / lexicographical order).
Then compare that? I'd recommend a key method or property for simplicity e.g.
#total_ordering
class Book:
#property
def _key(self):
return (self.author, self.year, self.title)
def __eq__(self, other):
return self._key == other._key
def __gt__(self, other):
return self._key > other._key
should do the trick and order your records by ascending author, ascending year of publication, and ascending title
That aside,
Python is not Java
All your trivial getters and setters are useless and redundant, just remove them outright. And getBookDetails should just be the implementation of your __str__.
BookCollection is similarly concerning, isEmpty is not a thing in Python, instead collections implement __len__ (and optionally __bool__ for efficiency). And the entire thing is a mess, why doesn't BookCollection just contain a list of books (or some other collection from the stdlib)? What's the purpose of making it some sort of ad-hoc half-assed linked list?
And it shoudl provide (or use) an iterator, you're implementing the same iteration scheme 3 different times for no reason.
Your naming scheme is also incorrect, Python normally uses snake_case for methods, and properties, and fields.

Printing sum of list items

What I need is to print the total a person has spent on products, I know the code is horrible but that's how I received the assignment. Never worked with Python so it's all a little mystery for me.
My result so far
The outcome should be 950 for Jeroen, 1175 for Martijn and 800 for Bart without printing them individually.
#start opdracht3 class
class opdracht3:
#start product class
class Product:
#constructor
def __init__(self, productname, price):
self.productname = productname
self.price = price
#end product class
#person class
class Person:
#constructor
def __init__(self, name, email, productlist):
self.name = name
self.email = email
self.productlist = productlist
#adding products to person's collection
def buyItem(self, item):
self.productlist.append(item)
#end person class
#collection of persons
persons = []
#defining person1 with the items he has bought
productlist1 = []
person1 = Person("Jeroen","jbm.mutsters#avans.nl", productlist1)
product1 = Product("Moto G7",150)
person1.buyItem(product1)
product3 = Product("iPhone",800)
person1.buyItem(product3)
#defining person2 with the items he has bought
productlist2 = []
person2 = Person("Martijn","m.dereus1#avans.nl", productlist2)
product2 = Product("iPhone",800)
person2.buyItem(product2)
product5 = Product("iPad",375)
person2.buyItem(product5)
#defining person2 with the items he has bought
productlist3 = []
person3 = Person("Bart","b.linsen#avans.nl", productlist3)
product4 = Product("iPhone",800)
person3.buyItem(product2)
#add person1 and person2 to the persons collection
persons.append(person1)
persons.append(person2)
persons.append(person3)
#generating output
for p in persons:
print(p.name)
for i in p.productlist:
print(i.productname)
print(i.price)
print("-----------------")
print("einde output")
print("***************")
#end generating output
#end opdracht3 class
Thanks in advance.
You can use the built-in sum to find the sum, and a list comprehension to get the prices from the items:
sum([x.price for x in p.productlist])
Same but in as a instance method:
class Person:
def __init__(self, name, email, productlist):
self.name = name
self.email = email
self.productlist = productlist
def buyItem(self, item):
self.productlist.append(item)
def get_sum_spend(self):
return sum([product.price for product in self.productlist])
Also, camel case methods naming typically is not used in Python. You can read more in pep8.
I added the method sum_product_prices to the person class which adds up the prices of the products in the persons productlist. Add the persons to the list persons and print out the return value of sum_product_prices. I removed the opdracht 3 class because it is not used.
#start product class
class Product:
#constructor
def __init__(self, productname, price):
self.productname = productname
self.price = price
#end product class
#person class
class Person:
#constructor
def __init__(self, name, email, productlist):
self.name = name
self.email = email
self.productlist = productlist
#adding products to person's collection
def buy_item(self, item):
self.productlist.append(item)
def sum_product_prices(self):
sum = 0
for product in self.productlist:
sum += product.price
return sum
#end person class
#collection of persons
persons = []
#defining person1 with the items he has bought
productlist1 = []
person1 = Person("Jeroen","jbm.mutsters#avans.nl", productlist1)
product1 = Product("Moto G7",150)
person1.buy_item(product1)
product3 = Product("iPhone",800)
person1.buy_item(product3)
persons.append(person1)
productlist2 = []
person2 = (Person("Martijn","x#y.com",productlist2))
person2.buy_item(product3)
product4 = Product("iPad",375)
person2.buy_item(product4)
persons.append(person2)
productlist3 = []
person3 = Person("Bart","a#b.com",productlist3)
person3.buy_item(product4)
persons.append(person3)
for person in persons:
print(person.name + " " + str(person.sum_product_prices()))

Shopping Cart and item class in python, issue with accessing objects from one class and using them in another

Attempting to create a program in python 3 that takes object(s) created from one class item to another, shoppingCart. The idea is to create a list of objects created by the item class using the shoppingCartclass, while still being able to access attributes of the item class such as price and quantity.
class item:
def __init__(self,n,p,q):
self.name = n
self.price = p
self.quantity = q
def show(self):
z = (str(self.name))
print(z)
self1 =("$")+(str(self.price))
print(self1)
def getName(self):
return self.name
def getPrice(self):
return ("$") + str(self.price)
def getQuantity(self):
return self.quantity
class shoppingCart:
def __init__(self, items):
self.items = []
def show(self):
print(self.items)
def addItem(self,item):
if item not in self.items:
self.items.append(item)
else:
item.q += 1
def deleteItem(self,item):
if item in self.items:
self.items.remove(item)
else:
return print("Not in Cart")
def checkOut (self):
total = 0
for i in self.items:
price = i[1]
total += price
return total
item1 = item("Chocolate",5 ,3)
item2 = item("Bacon",15,1)
item3 = item("Eggs",2,5)
c = shoppingCart([])
c.addItem(item1)
c.addItem(item2)
c.addItem(item3)
c.show()
print ("You have 3 items in your cart for a total of" (c.checkOut()))
c.removeItem(item3)
print ("You have 2 items in your cart for a total of" (c.checkOut()))
The above code currently creates two errors, firstly, the c.show is printing the IDs of the objects appended to the shopping cart. In addition, the checkOut method creates an error regarding price = i[1] saying that the item object does not support indexing. Alternate solutions to this problem that still bares some resemblance to my original code will be welcome!
First, c.show() prints the list, but you haven't defined __str__ or __repr__ for your classes, so you're stuck with the default representation. Try e.g.
def __str__(self):
return str(self.name)
Then you can:
print(map(str, self.items))
Alternatively, use your item.show:
for i in self.items:
i.show()
Second, in checkOut, i is an item, which you can't index into. If you want its price, use dot notation: i.price.

Categories