Using For loop with a class object - python

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.

Related

(Python) Why my inheritence does not work?

class Bin():
def __init__(self):
self.bin = {}
def add_to_bin(self, medId , medName):
self.bin[medId] = medName
def remove_by_id(self, id):
self.bin.pop(id)
def clean_bin(self):
self.bin.clear()
def check_ids(self):
list(self.bin.keys())
def check_names(self):
list(self.bin.values())
def check_inventory(self):
list(self.bin.items())
if __name__ == "__main__":
bin1 = Bin()
bin1.add_to_bin(100, "advil")
bin1.add_to_bin(200, "tylenol")
bin1.add_to_bin(300, "pepto-bismol")
bin1.check_inventory()
What am I doing wrong? I am so confused.
I am trying to create a medical storage system with multiple dictionaries. Whenever I try to run the code, it does not return anything.
Firstly there is no inheritance in your code. It is just a class and object code. Second you need to return data from your methods.
class Bin():
def __init__(self):
self.bin = {}
def add_to_bin(self, medId , medName):
self.bin[medId] = medName
def remove_by_id(self, id):
self.bin.pop(id)
def clean_bin(self):
self.bin.clear()
def check_ids(self):
return list(self.bin.keys())
def check_names(self):
return list(self.bin.values())
def check_inventory(self):
return list(self.bin.items())
if __name__ == "__main__":
bin1 = Bin()
bin1.add_to_bin(100, "advil")
bin1.add_to_bin(200, "tylenol")
bin1.add_to_bin(300, "pepto-bismol")
inventory = bin1.check_inventory()
print(inventory)
ids = bin1.check_ids()
print(ids)
names = bin1.check_names()
print(names)

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

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)

How to assign return value to __init__ value

I am trying to assign the return values of getItem and getBuyingType to the self variables in the __init__ method in my Ebay Scraper function. How can I do this? If it's not possible, is there another way to assign the outputs of these two functions to be part of the Ebay Scraper class? Item should be assigned to self.item and buying_type to self.buying_type.
class EbayScraper(object):
def __init__(self):
self.base_url = "https://www.ebay.com/sch/i.html?_nkw="
self.item =
self.buying_type =
self.url_seperator = "&_sop=12&rt=nc&LH_"
self.url_seperator2 = "&_pgn="
self.page_num = "1"
self.currentPage = 1
def getItem(self):
item = input("Item: ")
return item
def getBuyingType(self):
buying_type = input("Please specify a buying type (Auction or Buy It Now): ")
buying_type = buying_type.lower()
if buying_type == "auction":
return buying_type + "=1"
elif buying_type == "buy it now":
return buying_type + "=1"
else:
print("Invalid buying type specified.")
self.getBuyingType()
You can call functions inside __init__ method
def __init__(self):
...
self.item = self.getItem()
The proper way to do this is to simply pass arguments to __init__ to initialize the values. If you want to provide an interactive method for providing those arguments, define a class method.
class EbayScraper(object):
def __init__(self, item, buying_type):
self.base_url = "https://www.ebay.com/sch/i.html?_nkw="
self.item = item
self.buying_type = buying_type
self.url_seperator = "&_sop=12&rt=nc&LH_"
self.url_seperator2 = "&_pgn="
self.page_num = "1"
self.currentPage = 1
#classmethod
def prompt_user(cls):
item = input("Item")
while True:
buying_type = input("Please specify a buying type...").lower()
if buying_type in ('auction', 'buy it now'):
break
print("Invalid buying type specified")
return cls(item, buying_type + "=1")
e = EbayScraper.prompt_user()

how to call function dynamically

I have a class containing several lists as attributes and several add methods to append an object to a specific list based on its type.
My code reads a csv file containing the type of an object in order to create and add it to my cart.
My problem is that I'm testing the object type to call the right 'add' function using if elif syntax but this is not very nice and hard to maintain.
For example
import csv
class my_item():
def __init__(self, name):
self.name = name
class fruit(my_item):
pass
class vegetable(my_item):
pass
class meat(my_item):
pass
class fish(my_item):
pass
class shopping_cart():
def __init__(self):
self.fruits = []
self.vegetables = []
self.meat = []
self.fish = []
def add_fruit(self, o):
self.fruits.append(o)
def add_vegetable(self, o):
self.vegetables.append(o)
def add_meat(self, o):
self.meat.append(o)
def add_fish(self, o):
self.fish.append(o)
def __str__(self):
msg = ""
msg += "{:<25}= {:<5}\n".format('Total', str(len(self.fruits) + len(self.vegetables) + len(self.meat) + len(self.fish)))
for attrname in vars(self):
value = getattr(self, attrname)
if isinstance(value, list):
msg += " {:<23}= {:<5}\n".format(attrname, len(value))
return msg
def main():
input_f = 'input.csv'
my_cart = shopping_cart()
with open(input_f, 'r') as i:
rows = csv.reader(i, delimiter=';')
for row in rows:
item = globals()[row[0]](row[1])
if item.__class__.__name__ == 'fruit':
my_cart.add_fruit(item)
elif item.__class__.__name__ == 'vegetable':
my_cart.add_vegetable(item)
elif item.__class__.__name__ == 'meat':
my_cart.add_meat(item)
else:
my_cart.add_fish(item)
print (my_cart)
if __name__ == '__main__':
main()
Do you see any alternatives to the if elif block?
Thanks for your feedback.
Sure, you just need to create the function name dynamically and call it.
Be careful, this will works only if my_cart have add_{{ item name }} method.
def main():
input_f = 'input.csv'
my_cart = shopping_cart()
with open(input_f, 'r') as i:
rows = csv.reader(i, delimiter=';')
for row in rows:
item = globals()[row[0]](row[1])
item_name = item.__class__.__name__
item_add_func_name = 'add_{}'.format(item_name)
item_add_func = getattr(my_cart, item_add_func_name, None)
if item_add_func and callable(item_add_func):
item_add_func(item)
# if item.__class__.__name__ == 'fruit':
# my_cart.add_fruit(item)
# elif item.__class__.__name__ == 'vegetable':
# my_cart.add_vegetable(item)
# elif item.__class__.__name__ == 'meat':
# my_cart.add_meat(item)
# else:
# my_cart.add_fish(item)
print (my_cart)
May I suggest a simpler class design.
my_item is left as it-is and other classes fruit, vegetable etc. are removed
shopping_cart is modified such that self.items is a dictionary where the key is the name of item, fruit, vegetables, and the values are the list of those items
Then the code might look like as follows
import csv
from collections import defaultdict
class my_item:
def __init__(self, name):
self.name = name
class shopping_cart:
def __init__(self):
#Dictionary to hold items
self.items = defaultdict(list)
def add_item(self, type, name):
#Increment the count of the item by 1
self.items[type].append(name)
def __str__(self):
#Iterate through the dictionary and print all key/value pairs
msg = ""
for k,v in self.items.items():
msg += ' {}: {} '.format(k, v)
return msg.strip()
sc = shopping_cart()
sc.add_item('fruit', 'pomme')
sc.add_item('vegetable', 'dinde')
sc.add_item('meat', 'carotte')
sc.add_item('fish', 'saumon')
print(sc)
The output will look like
fruit: ['pomme'] vegetable: ['dinde'] meat: ['carotte'] fish: ['saumon']

Can I share data between different class instances in Python?

I have a class option, for which I create an instance z.
How can I use the optionbook from instance z in another instance of option, say y?
class option(object):
nextIdNum = 0
def __init__(self):
self.optionbook = {}
self.options = []
self.optioncomb = {}
def addopttobook(self,optiondescription):
self.idNum = option.nextIdNum
if optiondescription in self.optionbook.values() :
raise ValueError('Duplicate Option')
self.optionbook["Opt.ID." + str(self.idNum)] = optiondescription
option.nextIdNum += 1
def addoptocomb (self,option):
combID = 0
if option in self.optionbook.values():
if option in self.options:
raise ValueError('Duplicate Option')
self.combID = combID
self.options.append(str(list(self.optionbook.keys())[list(self.optionbook.values()).index(option)]) +":"+ option)
self.optioncomb["Optcomb.ID." + str(self.combID)] = self.options
self.combID +=1
else:
raise ValueError('Add options to optionbook first')
def __str__(self):
return str(self.optionbook)
def getOptionbook(self):
return self.optionbook.copy()
def getOptioncomb(self):
return self.optioncomb.copy()
z = option()
z.addopttobook('open the well')
y = option()
y.addoptocomb('open the well')
This gives me a ValueError "Add options to optionbook first" , I understand the error, y and z are different instances. I just want to know how to share data between different instances of same class.
You already defined a variable, that 'shares data between different instance': nextIdNum, so you can do the same for optionbook.
class option(object):
nextIdNum = 0
optionbook = {}
def __init__(self):
self.options = []
self.optioncomb = {}
... # rest of your code here
z = option()
z.addopttobook('z opens the well 1')
z.addopttobook('z opens the well 2')
y = option()
z.addopttobook('y opens the well 1')
y.addoptocomb('z opens the well 1')
print(option.optionbook)
print (option.optionbook == z.optionbook == y.optionbook)
Returns:
{'Opt.ID.0': 'z opens the well 1', 'Opt.ID.1': 'z opens the well 2', 'Opt.ID.2': 'y opens the well 1'}
True # >> The class itself as well as all instances share the same data.
You need a static variable in the option class, and extend your methods to be able to pass in a variable for which optionbook to use:
class option(object):
nextIdNum = 0
optionbook = {} # this variable is "static", i.e. not bound to an instance, but the class itself
def __init__(self):
self.optionbook = {}
self.options = []
self.optioncomb = {}
def addopttobook(self,optiondescription, book): # add book-param
self.idNum = option.nextIdNum
if optiondescription in self.optionbook.values() :
raise ValueError('Duplicate Option')
book["Opt.ID." + str(self.idNum)] = optiondescription
option.nextIdNum += 1
def addoptocomb (self,option, book): # add book-param
combID = 0
if option in book.values():
if option in self.options:
raise ValueError('Duplicate Option')
self.combID = combID
self.options.append(str(list(book.keys())[list(book.values()).index(option)]) +":"+ option)
self.optioncomb["Optcomb.ID." + str(self.combID)] = self.options
self.combID +=1
else:
raise ValueError('Add options to optionbook first')
def __str__(self):
return str(self.optionbook)
def getOptionbook(self):
return self.optionbook.copy()
def getOptioncomb(self):
return self.optioncomb.copy()
That way, you can access the static member optionbook via option.optionbook:
z = option()
# you can always access the static member by referencing it via the class-name
# it is not bound to any concrete instances
z.addopttobook('open the well', option.optionbook)
y = option()
y.addoptocomb('open the well', option.optionbook)
print(option.optionbook)

Categories