Confused about AttributeError in Python - python

I am trying to do the following project:
Imagine you have started up a small restaurant and are trying to make it easier to take and calculate orders. Since your restaurant only sells 9 different items, you assign each one to a number, as shown below.
Chicken Strips - $3.50
French Fries - $2.50
Hamburger - $4.00
Hotdog - $3.50
Large Drink - $1.75
Medium Drink - $1.50
Milk Shake - $2.25
Salad - $3.75
Small Drink - $1.25
To quickly take orders, your program should allow the user to type in a string of numbers and then it should calculate the cost of the order. For example, if one large drink, two small drinks, two hamburgers, one hotdog, and a salad are ordered, the user should type in 5993348, and the program should say that it costs $19.50. Also, make sure that the program loops so the user can take multiple orders without having to restart the program each time.
My code looks like this so far:
print "------------------Menu-------------------"
class Menu_Item():
def __init__(self, num,item,price):
self.num = num
self.item = item
self.price = price
def __repr__(self):
return "\n" + str(self.num) + ". " + self.item + " - $" + str(self.price) + ' dollars'
Strips = Menu_Item(1,'Chicken Strips', 3.50)
Fries = Menu_Item(2,"Fries",2.50)
Burger = Menu_Item(3,"Burger",4.00)
Hotdog = Menu_Item(4,"Hotdog",3.50)
Large_Drink = Menu_Item(5,"Large Drink",1.75)
Medium_Drink = Menu_Item(6,"Medium Drink", 1.50)
Milkshake = Menu_Item(7,"Milkshake", 2.25)
Salad = Menu_Item(8,"Salad", 3.75)
Small_Drink = Menu_Item(9,"Small Drink", 1.25)
Class_Items = [Strips,Fries,Burger,Hotdog,Large_Drink,Medium_Drink,Milkshake,Salad,Small_Drink]
print Class_Items
def take_order():
count = 0
string = raw_input("Enter your order")
order = []
for a in string:
order.append(a)
for food in Class_Items:
for b in order:
if b == Menu_Item.num:
count = count + Menu_Item.price
return count
else:
print "-"
take_order()
I am getting the following error. I have tried a ton of ways to make this work and I can't figure out why the compiler isn't recognizing the num attribute. Any suggestions as to why this is happening? Thanks!
Traceback (most recent call last):
File "python", line 43, in <module>
File "python", line 37, in take_order
AttributeError: class Menu_Item has no attribute 'num'

Why are you accessing Menu_Item here? That's the class itself; the item that you've got from the list is called food.

Menu_Item is the class. You attempted to access an attribute of the class. Think of a class like a blueprint for a house. You asked for the street address for the blueprint.
In Python, you're supposed to name classes with CamelCase by convention and PEP 8. So, MenuItem instead of Menu_Item. You are also supposed to name variables using separated_by_underscores. This way, you can easily distinguish between classes and normal objects.
I think what you want is:
for food in Class_Items:
for b in order:
if b == food.num:
...
This way, instead of comparing the blueprint's street address, you compare the actual house's street address. Python ≠ English; the blueprint is always Menu_Item and food will refer to a house. (assuming you don't explicitly say Menu_Item = ... or likewise food = ...)
Also, python doesn't have a compiler. It's not a compiled language.
You should inherit off of object by convention; class MenuItem(object):
The foods would be better implemented as classes with class attributes that inherit off of MenuItem.
Class attributes are attributes defined in the body of the class. For example:
class HotDog(MenuItem):
price = 1.5
would let you write HotDog.price and receive 1.5 as the answer.

You've got several problems here. Most notably the one pointed out by Daniel Roseman and uoɥʇʎPʎzɐɹC. However, after fixing that issue you will still have problems with your code.
In take_order() you need to move return count outside of your for loop otherwise you will return count after the first item is added. You will also need to change the input to an integer or b == food.num will never resolve to True.

In addition to the useful answers you received, I just wanted to point out that you can solve this problem with a simple function, without having to define a new class (the project didn't require that, according to what you wrote).
To begin with, you can create a dictionary of the items on the menu and their price:
menu_items={'1':['Chicken Strips',3.50],'2':['French Fries',2.50],'3':['Hamburger',4.00],'4':['Hotdog',3.50],'5':['Large Drink',1.75],'6':['Medium Drink',1.50],'7':['Milk Shake',2.25],'8':['Salad',3.75],'9':['Small Drink',1.25]}
After that, you can create a function that addresses you needs:
def total_order():
total=0
while True:
order=str(input('Please enter your order, or type "done" to terminate the program: '))
sum_order=0
if order=='done':
print('\nProgram terminated. The overall total order is: '+str(total)+'$')
return total
for number in order:
if number in menu_items:
sum_order+=menu_items[number][1]
total+=sum_order
print('The total for this order is: '+str(sum_order)+'$\n')
total_order()
The function keeps executing until you type the word 'done', and it prints the amount of money spent for each order, as well as the total amount of money spent (for all the orders together).

Related

How can I create a program that count votes that are being put by the user

I need to make 3 political parties like in an election. The program should ask "for which will you vote?" (showing the 3 political options), after 10 the user randomly inserts 10 votes, the program should count the votes and print the results.
I'm new to programming, I really don't know what I'm doing
print("today is election day! for who will u vote?")
polls=print("PLD","PRM","PRD")
1) In your question, you stated "after 10...", after 10 what?
Im assuming that if was just a typo.
Here's the code for the program. All you need to do is figure out how to stop asking once it the vote count is greater than or equal to 10. You learn and retain information best when you struggle, trust me.
If you have any questions about the syntax used, feel free to drop a comment.
parties = ['PLD', 'PRM', 'PRD']
max_votes = 10
num_votes = 0
print('~'*40)
print(f'\n~ Today is election day!\n~ You have {vote_count} votes to use\n~ Use them wisely!\n')
print('~'*40)
print(f' Polical Parties: {parties[:]}')
print('~'*40,'\n')
"""
As declared above, "num_votes" is the variable that is being used to keep
track of how many votes the user has used so far.
The += operator adds the value of the variable on the right to the existing
value of the variable on the left. It would be the same as saying:
>>> num_votes = num_votes + PLD_votes
So, its just saving the number of votes used to the varible "num_votes".
"""
PLD_votes = int(input(f'\nHow many votes for "{parties[0]}": '))
num_votes += PLD_votes
num_votes = input(f'\nHow many votes for "{parties[1]}": ')
num_votes += PRM_votes
PRD_votes = input(f'\nHow many votes for "{parties[2]}": ')
vote_count += PRD_votes
print('Here are the results...\n')
print(f'{parties[0]}: {PLD_votes}\n{parties[1]}: {PRM_votes}\n{parties[2]}: {PLD_votes}')
"""
The use of "f" and "{}" within strings is a way of formating the string to return letters with variables in them.
Example: print(f'Number of votes: {num_votes}') *mind the 'f'*
Here, typing 'f' before the quotations tells the program that you are going to be using "{}" within the string. What goes inside of the curlies "{}" are variables that you want to print along with the string. I prefer this
There are many different ways of accomplishing this:
Concatenation:
>>> print('Number of votes' + num_votes)
Using %d ('d' for numbers; for variable which contain strings you would use '%s'):
>>> print('Number of votes %d')
There are more ways of doing it, I just prefer using {} because to me it seems more straightforward to read.
"""

How to match input with elements in list/dictionary in Python3

I'm very new at coding, and I'm trying to create a shop list with items and prices on it.
That is, once typed in all the items, the function should calculate the sum and stop the moment you exceed the budget.
So I wrote something like:
def shoplist():
list={"apple":30, "orange":20, "milk":60......}
buy=str(input("What do you want to purchase?")
If buy in list:
While sum<=budget:
sum=sum+??
shoplist ()
I really don't know how to match the input of an item with the price in the list...
My first thought is to use 'if', but it's kinda impractical when you have more than 10 items on the list and random inputs.
I'm in desperate need of help....So any suggestions would be nice!! (or if you have a better solution and think me writing it this way is complete garbage... PLEASE let me know what those better solutions are😭😭😭
The code you post will not run in python. list is a builtin and should not be used for a variable name, and is doubly confusing since it refers to a dict object here. input() already returns a str so the cast has no effect. if and while should be lowercase, and there is no indentation, so we have no way of knowing the limits of those statements.
There are so many things wrong, take a look at this:
def shoplist(budget):
prices = {"apple":30, "orange":20, "milk":60}
# Initialise sum
sum = 0
while sum <= budget:
buy = input("What do you want to purchase?")
# Break out of the loop if the user hts <RETURN>
if not buy: break
if buy in prices:
sum += prices[buy] # This gets the price
else:
print("Invalid item", buy)
shoplist(142)
So what have I changed? The budget has to come from somewhere, so I pass it in as a parameter (142, I made that up). I initialise the sum to zero, and I moved the while loop to the outside.
Notice as well lots of whitespace - it makes the code easier to read and has no effect on performance.
Lots of improvements to make. The user should be shown a list of possible items and prices and also how much budget there is left for each purchase. Note as well that it is possible to go over budget since we might only have 30 in the budget but we can still buy milk (which is 60) - we need another check (if statement) in there!
I'll leave the improvements to you. Have fun!
Take a look at this as an example:
# this is a dictionary not a list
# be careful not using python reserved names as variable names
groceries = {
"apple":30,
"orange":20,
"milk":60
}
expenses = 0
budget = 100
cart = []
# while statements, as well as if statements are in lower letter
while expenses < budget:
# input always returns str, no need to cast
user_input = input("What do you want to purchase?")
if user_input not in groceries.keys():
print(f'{user_input} is not available!')
continue
if groceries[user_input] > budget - expenses:
print('You do not have enough budget to buy this')
user_input = input("Are you done shopping?Type 'y' if you are.")
if user_input == 'y':
break
continue
cart.append(user_input)
# this is how you add a number to anotherone
expenses += groceries[user_input]
print("Shopping cart full. You bought {} items and have {} left in your budget.".format(len(cart), budget-expenses))
I've made some changes to your code to make it work, with explanation including using comments indicated by the # symbol.
The two most important things are that all parentheses need to be closed:
fun((x, y) # broken
fun((x, y)) # not broken
and keywords in Python are all lowercase:
if, while, for, not # will work
If, While, For, Not # won't work
You might be confused by True and False, which probably should be lowercase. They've been that way so long that it's too late to change them now.
budget = 100 # You need to initialize variables before using them.
def shoplist():
prices = { # I re-named the price list from list to prices
'apple' : 30, # because list is a reserved keyword. You should only
'orange' : 20, # use the list keyword to initialize list objects.
'milk' : 60, # This type of object is called a dictionary.
} # The dots .... would have caused an error.
# In most programming languages, you need to close all braces ().
# I've renamed buy to item to make it clearer what that variable represents.
item = input('What do you want to purchase? ')
# Also, you don't need to cast the value of input to str;
# it's already a str.
if item in prices:
# If you need an int, you do have to cast from string to int.
count = int(input('How many? '))
cost = count*prices[item] # Access dictionary items using [].
if cost > budget:
print('You can\'t afford that many!')
else:
# You can put data into strings using the % symbol like so:
print('That\'ll be %i.' % cost) # Here %i indicates an int.
else:
print('We don\'t have %s in stock.' % item) # Here %s means str.
shoplist()
A lot of beginners post broken code on StackOverflow without saying that they're getting errors or what those errors are. It's always helpful to post the error messages. Let me know if you have more questions.

Answer Error, Only outputting Zero

I am coding in python and I cannot seem to figure out why when the amount of tickets sold is entered it does not calculate the full price of the tickets that were sold. Any help is appreciated, Thanks.
aLimit=300
bLimit=500
cLimit=100
aPrice=20
bPrice=15
cPrice=10
ticketSold=1
totalIncome=0
def Main():
getTickets(aLimit)
sectionIncome=calcIncome(ticketSold,aPrice)
sectionIncome+=totalIncome
print("The theater generated this much money from section A "+
str(sectionIncome))
getTickets(bLimit)
sectionIncome=calcIncome(ticketSold,bPrice)
sectionIncome+=totalIncome
print("The theater generated this much money from section B "+
str(sectionIncome))
getTickets(cLimit)
sectionIncome=calcIncome(ticketSold,cPrice)
sectionIncome+=totalIncome
print("The theater generated this much money from section C "+
str(sectionIncome))
print("The Theater generated "+str(totalIncome)+" total in ticket sales.")
def getTickets(limit):
ticketSold=int(input("How many tickets were sold? "))
if (ticketsValid(ticketSold,limit)==True):
return ticketSold
else:
getTickets(limit)
def ticketsValid(Sold,limit):
while (Sold>limit or Sold<0):
print("ERROR: There must be tickets less than "+
str(limit)+" and more than 0")
return False
return True
def calcIncome(ticketSold,price):
return ticketSold*price
Main()
How to debug your (small) program
Okay so let's start from the top and go line-by-line. There's a lot of issues here.
aLimit=300
bLimit=500
cLimit=100
aPrice=20
bPrice=15
cPrice=10
ticketSold=1
totalIncome=0
These are all globals since you defined them in the module scope. That's a Bad Thing. Don't do it. If they're constants, use CAPS to mention that, but they should still not be global.
def Main(): # I mentioned in my comment, but Capitals are classes
# by convention, use def main() instead
getTickets(aLimit)
Let's stop and look at getTickets() so we can follow execution
def getTickets(limit): # camelCase is not advised per PEP8, but it's still around
# so I wouldn't worry about this one so much as Capitalized
ticketSold=int(input("How many tickets were sold? "))
# perfect implementation, though be prepared for users who
# will type forty instead of 40!
if (ticketsValid(ticketSold,limit)==True):
return ticketSold
# so any time you write `if ___ == True`, stop and realize that the compare
# is unnecessary. if ticketsValid(ticketSold,limit) works just as well!
else:
getTickets(limit)
# wha-? If the tickets aren't valid, we're RECURSING??! This is an infinite loop.
# are you doing this to prompt for more input if tickets aren't valid? That's Bad
Okay so you invoked ticketsValid in there, so let's look there now...
def ticketsValid(Sold,limit): # another Capital here!
while Sold > limit or Sold < 0: # this should be an if??
print ("...")
return False
return True
# Since you have a set amount, this is MUCH easier written as:
## def ticketsValid(sold,limit):
## return 0 < sold < limit
# but should this be <=?
Alright, back to main--ahem--Main....
def Main():
...
sectionIncome = calcIncome(ticketSold,aPrice)
And hop back to calcIncome
def calcIncome(ticketSold,price):
return ticketSold*price # why not just substitute this???
Main again
def Main():
...
sectionIncome += totalIncome
# this sets sectionIncome equal to the current value of sectionIncome
# plus the current value of totalIncome, which is currently zero.
Then basically the whole thing gets repeated down the function. There's your issue, the += adds zero to sectionIncome instead of adding sectionIncome to totalIncome!
The better way to do this!
Here's the problem. You're trying to use functional programming to do object-oriented tasks. Most of these kind of issues are when new programmers who are interested in video games think that the best task to learn programming is a text adventure. Unfortunately, the best languages for text adventures (those that easily implement a Finite State Machine) are not usually those that beginners start with, so it's hard to implement WELL!
In your case, you should be creating objects to do the workload for you. Python does this elegantly, but it's rarely in beginning tutorials. As an example, I wrote out a bit that does exactly what you did (defines three sections of seating in a theater and sells one ticket per section)
class Section(object):
def __init__(self,price,limit):
self.price = price
self.tickets_sold = 0
self.limit = limit
#property
def sales(self):
return self.price*self.tickets_sold
def sell(self,qty=1):
if not isinstance(qty,int): raise TypeError("Must sell an int of tickets")
if qty < 1: raise ValueError("Must sell positive tickets")
qty = min(qty,self.limit-self.tickets_sold)
self.tickets_sold += qty
# optional print statement for the user
class Theater(object):
def __init__(self,sections):
self.sections = sections
#property
def sales(self):
return sum(section.sales for section in self.sections)
theater = Theater([Section(20,300),
Section(15,500),
Section(10,100)])
for section in theater.sections:
section.sell(1)
print(theater.sales)
The big problem with this is just that you don't know how to do it. Creating an object that will stay constant, then throw several instances of it around with specific attributes is precisely the approach I would favor in this circumstance.
read up on the += operator. totalIncome is only ever set to 0.
You need to replace sectionIncome+=totalIncome with totalIncome+=sectionIncome
Code
aLimit=300
bLimit=500
cLimit=100
aPrice=20
bPrice=15
cPrice=10
ticketSold=1
totalIncome=0
def Main():
getTickets(aLimit)
sectionIncome=calcIncome(ticketSold,aPrice)
totalIncome=sectionIncome
print("The theater generated this much money from section A "+str(sectionIncome))
getTickets(bLimit)
sectionIncome=calcIncome(ticketSold,bPrice)
totalIncome+=sectionIncome
print("The theater generated this much money from section B "+str(sectionIncome))
getTickets(cLimit)
sectionIncome=calcIncome(ticketSold,cPrice)
totalIncome+=sectionIncome
print("The theater generated this much money from section C "+str(sectionIncome))
print("The Theater generated "+str(totalIncome)+" total in ticket sales.")
def getTickets(limit):
ticketSold=int(input("How many tickets were sold? "))
if (ticketsValid(ticketSold,limit)==True):
return ticketSold
else:
getTickets(limit)
def ticketsValid(Sold,limit):
while (Sold>limit or Sold<0):
print ("ERROR: There must be tickets less than "+str(limit)+" and more than 0")
return False
return True
def calcIncome(ticketSold,price):
return ticketSold*price
Main()
sectionIncome+=totalIncome
This is the wrong way around. To add to totalIncome the value of sectionIncome, the syntax is
totalIncome+=sectionIncome
You will allso need to add global totalIncome to the beginning of Main -- or, better yet, do away with the global variables completely, like you have often been told before.
Finally, your getTickets function returns a calculated value, but the code which calls it doesn't store that result anywhere. Instead, you simply set ticketSold=1 in the global initialization, then use that as the multiplier instead of the actual number of tickets input by the user.
As a general observation, you have a lot of repetitive code, while the functions you do have are not very useful (they do not encapsulate complex behavior, nor repeated functionality). If you are a beginner, concentrate on a straightforward flow, then factor out complex repeating operations to loops or functions. Perhaps something like this:
def income ():
total = 0
for ticket_type, limit, price in [('A', 300, 20),
('B', 500, 15),
('C', 100, 10)]:
print "How many %s tickets sold? (Max %d):" % (ticket_type, limit),
sold = -1
while sold < 0 or sold > limit:
if sold != -1:
print "Sorry. Try again:",
sold = raw_input()
try:
sold = int(sold)
except:
pass
total += sold*price
print "total %d" % total
income()
Please also note the user-friendly gesture of indicating the maximum allowed for each category in the input prompt (-:
The loop driver is a bit of a wart; a slicker way to do that would be to declare a class TicketCategory and have three instances A, B, and C with methods to report back their name, price, and available amounts, but that's for later.

Model methods stop working correctly after first call

I have defined two models for retailers and items in their stock. Product is defined in another app. I defined two model methods to get and add stock items. Here is the relevant part of the code:
class Retailer(models.Model):
name = models.CharField(max_length=100)
#property
def stock_items(self):
return StockItem.objects.filter(retailer__id=F('id'))
def add_stock_item(self, product_id):
try:
print "Checking if it's already in stock"
self.stock_items.get(product__id=product_id)
print "It's already in stock"
except ObjectDoesNotExist:
try:
print "Adding item to stock"
product = Product.objects.get(pk=product_id)
StockItem.objects.create(retailer=self, product=product)
print "Added to stock"
except Product.DoesNotExist:
print "Such product doesn't exist"
def __unicode__(self):
return self.name
StockItem(models.Model):
retailer = models.ForeignKey(Retailer)
product = models.ForeignKey(Product)
def __unicode__(self):
return "%s - %s %s" % (self.retailer, self.product.brand, self.product)
When I want to use these model methods, something weird happens. They stop working correctly after adding the first item (In these examples, product 1 is 16 GB iPhone and Product 2 is 32 GB iPhone).
First let's add some products to our stock:
>>> r = Retailer.objects.get(pk=1)
>>> r.stock_items
[]
>>> r.add_stock_item(1)
Checking if it's already in stock
Adding item to stock
Added to stock
>>> r.add_stock_item(2)
Checking if it's already in stock
Adding item to stock
Added to stock
So far so good. Now let's try adding products again to see how it handles errors:
>>> r.add_stock_item(1)
Checking if it's already in stock
It's already in stock
>>> r.add_stock_item(2)
Checking if it's already in stock
Adding item to stock
Added to stock
What? Why did it add product 2 again. It was supposed to show a message similar to product 1. Let's see our stock:
>>> r.stock_items
[<StockItem: hh - Apple iPhone 4S 16GB>]
What happened to product 2? Did it fail to add it to database?
[<StockItem: hh - Apple iPhone 4S 16GB>, <StockItem: hh - Apple iPhone 4S 32GB>, <StockItem: hh - Apple iPhone 4S 32GB>]
Apparently not. It was added to database, but somehow our program fails to check it correctly. Only the first product added to stock is shown by calling r.stock_items. Restarting shell doesn't change the situation either, so I guess the reason couldn't be because of when the function is evaluated.
Why does this happen and how can I fix it?
Try to remove #property and change the method to this:
def stock_items(self):
return self.stockitem_set.all()
The reason why your method was failing is because that expression doesn't do what you think it does. The F() syntax is for comparing values within the same row: so that expression was checking that the related retailer ID was the same as the current row's ID. It so happened that this was true for the first item, but it would never be true of any subsequent items, because the row ID has incremented with the new items but the retailer ID remains the same.

MLM downline distribution count

I make my first MLM software and I think I managed to code how to get the points from the downline even though it is a recursive problem I didn't use recursion and I might refactor to a recursive version if that seems better. With our system, the level of a distributor is measured i number of silvers and for each product that gets sold the promotion/bonus/score/points works upline so if Bob is the sponsor of Alice and Alice makes a purchase then Bob will get points measured in number of silvers for that purchase. I added a business function to my user class:
def this_month_non_manager_silver(self):
silver = 0
today = date.today()
timeline = date(today.year, today.month, 1)
downline = User.query(User.sponsor
== self._key).fetch()
distributor = self
while distributor.has_downline():
downline = User.query(User.sponsor == distributor.key).fetch()
for person in downline:
orders = model.Order.all().filter('buyer_id =' , person.key.id()).filter('created >' , timeline).filter('status =', 'PAID').fetch(999999)
for order in orders:
for idx,item in enumerate(order.items):
purchase = model.Item.get_by_id(long(item.id()))
amount = int(order.amounts[idx])
silver = silver + amount*purchase.silver/1000.000
distributor = person
return silver
What might be to do is now just a % on the silver according to the depth of the order.
The code actually output the correct result for an order downline but I didn't yet test it extensively and I wonder if you think the code looks strange and if I have thought of everything since the models are somewhat complicated / advanced. The user class is from webapp2 and I could use a subclass but I didn't have time to do that so I just put in the method to the user class that's there and now I can call it from Jinja2 like {{user.this_month_non_manager_silver}}
Recursion might to be right way to do this but isn't my solution still OK and I can move on and keep this code for now or do you think it is not acceptable?
Thanks for any constructive criticism.
The main problem I see here is that you're essentially trying to do a breadth-first search (you look at all the users who are below the distributor, then look at all of the users below those distributors, etc etc), but each time the while loop loops you're only looking at the users below the last distributor.
If we break down the important parts into something python-ish, you get this:
distributor=self
while distributor.has_downline():
for person in distributor.downline:
distributor = person
As you can see, the value of distributor after the first set of downlines are accessed is the last distributor in the user's downline. Then the next time the for loop is run, you're only looking at the last distributor's downline.
Traditionally a tree-walking algorithm is either recursive or loop-based with a stack. Generally you will choose one or the other based on memory constraints. To keep the solution iterative, you'd need to rewrite the above python-ish code like this:
downlinestack = []
distributor=self
downlinestack += distributor.downline
while downlinestack:
downline = downlinestack.pop()
for person in downline:
downlinestack.append(person.downline)

Categories

Resources