pop from empty list error in car app - python

I'm mostly new to this so apologies in advance if the answer is blindingly obvious to this. For a school assignment (and out of interest also) I'm building a sort of basic car app that uses lists to store cars (objects) as they are made then a separate list to record cars that are rented.
The rent process works perfectly fine and when I tested it it was appending a car to my rentedcars list, however when I call it (rentedcars) later in a separate function its saying that it cannot pop an empty list.
I assumed this was because the list was being modified inside a function, however when I returned the outputed modified list and assigned a variable to the function for later use it gave me the error that I was calling a variable before assigning it and giving the variable a global definition didn't resolve it.
The segment of code is below, anyone have any thoughts? It would be much appreciated. I've looked this sort of problem a couple of times on the forums here but the solutions (at least as I tried to implement them) didn't seem to fix it.
The function rental_system is called later, I've just shown the section I'm having problems with due to size, all lists for the 4 types of car are made under init self. etc and work.
def rent(self, car_list, rented_cars, amount): # Process to rent a car function
if len(car_list) < amount:
print 'Not enough cars in stock' # Make sure enough cars in stock
return
total = 0
while total < amount:
carout = car_list.pop() # Pop last item from given car list and return it
rented_cars.append(carout) # Then append to a new list of rented cars that are now unavailable
total = total + 1
print 'Make: ' + carout.getMake()
print 'Colour: ' + carout.getColour()
print 'Engine Size(Cylinders): ' + carout.getEngineSize()
print 'You have rented ' + str(amount) + ' car(s)'
return rented_cars
def rented(self, car_list, rented_cars, amount): # Process for returning cars
total = 0
while total < amount:
carin = rented_cars.pop()
car_list.append(carin)
total = total + 1
print 'You have returned' +str(amount) + 'car(s)'
return rented_cars, car_list
def rental_system(self):
rentedcars = []
rented = raw_input('Are you returning or renting a car? Type either return/rent ')
if rented.lower() == 'return': # Return system
type = raw_input('Are you returning a petrol, electric, diesel or hybrid car? ')
amount = raw_input('How many would you like to return? ')
if type == 'petrol':
self.rented(self.petrolcars, rentedcars, amount)
elif type.lower() == 'diesel':
self.rented(self.dieselcars, rentedcars, amount)
elif type.lower() == 'hybrid':
self.rented(self.hybridcars, rentedcars, amount)
elif type.lower() == 'electric':
self.rented(self.electriccars, rentedcars, amount)
else:
print 'Error, please check your spelling'
return
if rented.lower() == 'rent':
Rental process
answer = raw_input('What type of car would you like? Type: petrol/diesel/hybrid/electric ')
amount = int(raw_input('How many of that type of car?'))
if answer.lower() == 'petrol':
self.rent(self.petrolcars, rentedcars, amount)
elif answer.lower() == 'diesel':
self.rent(self.dieselcars, rentedcars, amount)
elif answer.lower() == 'hybrid':
self.rent(self.hybridcars, rentedcars, amount)
elif answer.lower() == 'electric':
self.rent(self.electriccars, rentedcars, amount)
else:
print 'Error, please check your spelling'
return

The problem is that you are passing an empty list through the rental_system method to the rented method.
You have defined rentedcars = [] in rental_system method and without modifying it you are trying to pop from it in the rented method.
Why don't you add the rented_cars as an attribute in your class design?

Related

Text Adeventure python sell system

Credits to https://stackoverflow.com/users/5003756/james for answering my previous post Python Text adventure Selling, check if its in list with
def sell(player_inventory):
print('Available to sell::')
for i, stuff in enumerate(player_inventory, 1):
print(i, stuff)
sold = input('what item number do you want to sell? ("q" to exit)')
if sold == 'q':
return player_inventory
try:
sold = int(sold)
except ValueError:
print('Please use the item number')
return player_inventory
if sold <= len(player_inventory):
print('successfully sold!!')
player_inventory.pop(sold - 1)
return player_inventory
So anyways, thanks to James we now have a sell function which runs perfectly fine. But the thing is, I want to make it so the way the money gets added to my
player_money
How I could add money in there? When I run the sell function, it does take the item away from my inventory, but doesn't add money to
player_money
if sold <= len(player_inventory):
print('successfully sold!!')
player_inventory.pop(sold - 1)
player_money(add + amount)
return player_inventory
you have to add a function where the items amount sold is stored and then that amount would be added to the function of the money in the players inventory.

Changing a variable in a def function

Okay, weird question. So I'm making a text adventure game for a school project, and I'm making a shop system. It's supposed to only allow you to buy one of each item, with the exception of potions.
schoice = str(input("> "))
def shopresults(item, itemvar, price):
if schoice == str(item):
if itemvar == 0 and gold >= price:
print("Here ya go! One " + str(item) + " coming right up!")
# itemvar = 1 this should change the variable determining the status of the item, e.g. swordfire1 or swordfire2
gold == gold - price
if item == "fire sword" or itemvar == "water sword" or itemvar == "thunder sword":
freesword = 0
elif itemvar == 1 and (item != potion1 or item != potion2 or item != potion3):
print("You already have that, kiddo!")
elif gold < price:
print("You're a little short on gold there, bud...")
shopresults("fire sword", swordfire1, (100 - (100 * freesword)))
shopresults("flame sword", swordfire2, 500)
How do I change the variable that is called before you get into the shopresults program, in this case swordfire1, instead of the itemvar itself? swordfire1 determines if you have the 1st fire sword, and there's variables like this for every weapon. Ignore the freesword variable, you basically get one free sword in the game, and that's not the problem as far as I know. I know this is confusing, but please help if you can.
I guess I'm wondering what is the value of swordfire1 and swordfire2- they look like integers? My thinking is you should think about creating weapon objects and maintaining a registry of weapons. Based on the status, call your registry and return your weapon object to that variable. When I say registry you can use a simple dict or you can design a factory like pattern.
Variable assignment is done with = not ==. And you need combine the conditions with parentheses:
schoice = str(input("> "))
def shopresults(item, itemvar, price):
if schoice == str(item):
if (itemvar == 0) and (gold >= price):
print("Here ya go! One " + str(item) + " coming right up!")
# itemvar = 1 this should change the variable determining the status of the item, e.g. swordfire1 or swordfire2
gold = gold - price
if (item == "fire sword") or (itemvar == "water sword") or (itemvar == "thunder sword"):
freesword = 0
elif (itemvar == 1) and (item != potion1) or (item != potion2) or (item != potion3):
print("You already have that, kiddo!")
elif gold < price:
print("You're a little short on gold there, bud...")
shopresults("fire sword", swordfire1, (100 - (100 * freesword)))
shopresults("flame sword", swordfire2, 500)

How to fix my IF statement so I cant remove and append items from a list

I'm currently writing up a simple program to manage a car yard for a rental company, i've gotten to the end with no real issues until now. To illustrate what I mean i'll posted my code and then my issue.
# class for Car_Yard
class CarYard():
def __init__(self, listOfCars):
self.availableCars = listOfCars
def carYardCarsAvailable(self):
print("Available Cars: ")
for car in self.availableCars:
print(car)
def carYardRentCar(self, rentCar):
if rentCar in self.availableCars:
print("Congratulations on renting your new car, here\'s the keys")
self.availableCars.remove(rentCar)
else:
print("We currently don't have that car in our yard")
def carYardReturnCar(self, rentCarReturn):
self.availableCars.append(rentCarReturn)
print("You have returned the car. Thank You!")
# class for Buyer and his/hers actions
class Buyer():
def buyerRentCar(self):
print("Which car would you like to rent out?" )
self.car = input()
return self.car
def buyerReturnCar(self):
print("Which car would you like to return? ")
self.car = input()
return self.car
# create objects from class and pass a list of cars to the car yard
carYard = CarYard (['Mazda','Holden','Ford','Porsche','Honda','VW','Toyota','Kia'])
buyer = Buyer
# infinite loop
while True:
print()
print("Enter 1 to see our wide range of cars")
print("Enter 2 to rent a car")
print("Enter 3 to return a car")
print("Enter 4 to leave the rental yard")
print()
userInput = int(input())
if userInput is 1:
carYard.carYardCarsAvailable()
elif userInput is 2:
rentCar = buyer.buyerReturnCar
carYard.carYardRentCar(rentCar)
elif userInput is 3:
rentCarReturn = buyer.buyerReturnCar
carYard.carYardReturnCar(rentCarReturn)
elif userInput is 4:
quit()
The issue that i'm having is when I run my code and enter 2 it automatically skips to the line "we currently don't have that car in our yard" and when I enter 3 is says "You have returned the car. Thank you!".
I'm trying to figure out why my code is not called the Buyer class to request for the input. Any suggestions on what I might be missing?
You shouldn't use is like that. The is operator tests whether 2 objects are the same, which is not the same as testing whether their values are equal. What you actually want is an equality test (e.g. userInput == 1).
Anyway, the source of your problem is that you're passing around methods instead of the values that are returned by those methods. For instance this may work better:
buyer = Buyer()
...
elif userInput == 2:
rentCar = buyer.buyerReturnCar()
carYard.carYardRentCar(rentCar)
By passing buyer.buyerRentCar you're passing a method to carYardRentCar, and naturally it's not able to match that method against anything in the list of cars. What you want is to pass a string that is returned by carYardRentCar(). This will cause that method to get invoked, asking the user for input, and then the result of that will get passed along, which is what you want

How to refactor while loop with too much if, elif statement to function

I'm new here and I have a problem with too much if, else statement in while loop. I want to refactor it to function, but I don't have any idea how to do it.
My code:
brand = input("Please select a brand...")
if brand.lower() == "XX" or sex == "1":
print("You selected a XX...")
while True:
product = input()
if product.lower() == "apple" or product == "1":
print("You selected Apples!\n")
while True:
size_schema = input()
if size_schema.lower() == "in" or size_schema.lower() == "inch" or size_schema == "1":
while True:
apple_size = float(input())
if 8.5 <= apple_size <= 12.0:
real_apple_size = round(apple_size, 2)
print("Your apple size is {} inch!".format(real_apple_size))
cursor = size_guide.find({})
for document in cursor:
a = document['Product']['Apple']['INCH']
try:
b = [float(x) for x in a if x != '']
result = min(enumerate(b), key=lambda i: abs(i[1] -
float(real_apple_size)))
c = str(result[1])
except ValueError:
pass
real_apple_size = str(real_apple_size)
if real_apple_size in document['Product']['Apple']['INCH']:
index = document['Product']['Apple']['INCH'].index(real_apple_size)
print("We have this apples from {} brand!"
.format(document['Brand']))
elif c in document['Product']['Apple']['INCH']:
last_list_value = next(s for s in reversed(a) if s)
index = document['Product']['Apple']['INCH'].index(c)
real_apple_size = float(real_apple_size)
print("SORRY! We don't have exactly your size, "
"but we have similar size from {} brand!"
.format(document['Brand']))
else:
print("Sorry, We don't have apples for you from {} brand!"
"Check our other products!"
.format(document['Brand']))
else:
print("Please select your apple size in range 8.5-12.0 inch!")
continue
break
I want to reduce this code and insert it in function.
Better (though probably not best) functional code would be a set of functions that are reusable, and each do one (or a very small number) of things. For example:
def get_product():
brand=input("What brand?")
#input validation logic
product=input("What product?")
#input validation for product given brand
size=input("What size?")
#input validation given brand and product
color=input("What color? (enter 'none' for no color)")
#That's right, more validation
return brand, prod, size, color
def prod_lookup(brand, prod, size, color):
cursor = size_guide.find({})
for document in cursor:
#lookup product with logic as in your post
if __name__ == "__main__":
brand, prod, size, color = get_product()
prod_lookup(brand, prod, size, color)
Again, this is just an example of one way to do it that would be much less messy. If you need to update your list of available products, for example, you only have to adjust one part of one function, rather than choosing from a deeply nested bunch of conditionals and loops.
I'm sure there are better ways, but hopefully this gives you some idea where to start thinking.
Adding one possible implementation of input validation with product lookup. This way, your brand will always be the product number rather than the string, which is usually a faster lookup:
brand_dict={'xx':'1','yy':'2'}
while True:
brand=input("Enter brand: ").lower()
if brand in brand_dict.keys():
brand=int(brand_dict[brand])
break
elif brand in brand_dict.values():
brand=int(brand)
break
else:
print("Brand not recognized. Try again!")
First, just wrap the whole thing in one function
def foo():
brand = input("Please select a brand...")
if brand.lower() == "XX" or sex == "1":
# etc.
Now, note that your first if statement encompasses the rest of the function, and there is no else clause. That is, if the condition fails, you'll fall through to the end of the function and implicitly return. So just return explicitly if the condition does not* hold. This lets you immediately dedent the bulk of your code.
def foo():
brand = input("Please select a brand...")
if brand.lower() != "XX" and sex != "1":
return
print("You selected a XX...")
# etc
Repeat this process, either returning or breaking out of the enclosing infinite loop, for each of your else-less if statements.

Python fill-in-the-blanks code

I am a programming beginner and I am trying to build a fill-in-the-blank quiz. I am almost finished but I am stuck on 2 problems I am not able to solve, whatever I do. I would really appreciate your help with this. Thank you for helping me with this!
If you try to run the code and play the game:
1) It prints the quiz according to the difficulty(easy-insane) and quiz you want to play(apple, bond and programming quiz) which is great but afterwards it prompts you to choose difficulty again (the player_level() function keeps going even though the player/user has already chosen the difficulty level. I don't really understand why it does it? The player_level() procedure seems perfectly okay and logical to me.
2) The errors:
a) local variable blanks_index referenced before assignment
b) global name list_of_answers is not defined.
I know that it is related to the initialize_game() function but I don't know how to change the code so it refers all the variables (blanks_index, answers_index, player_lives) correctly.
It could be solved by creating global variables(I guess) but that is not a good practice so I am trying to avoid it. Formerly, the whole function initialise_game() and play_game() were one function, but as there are over 25 lines of code in one function, it is not a good practice as it is long and messy and I know that I can separate it but I don't know how.
Here is the code:
"""3 diffferent quizzes : Apple quiz, James Bond quiz, Programming quiz"""
"""Quiz and answers about Apple"""
Apple_quiz = ("The most valuable company in terms of market cap in 2016 is, ___1___."
"It was founded in ___2___. Its flagship product is called ___3___."
"___1___ has many competitors, the biggest rival is ___4___,founded by"
" nobody but the richest man on the planet,___5___ ___6___.")
list_of_answers_Apple = ["Apple", "1976", "Iphone", "Microsoft", "Bill", "Gates"]
"""Quiz and answers about Bond"""
Bond_quiz = ("James Bond is agent ___1___. He serves his country,___2___ ___3___"
" against its enemies. His car of choice is usually ___4___ ___5___."
" His favorite drink is ___6___.")
list_of_answers_Bond = ["007", "United", "Kingdom", "Aston", "Martin", "Martini"]
"""Quiz and answers about programming basics"""
Programming_quiz = ("___1___ are created with the def keyword. ___1___ are also called ___2___"
" You specify the inputs a ___1___ take by adding ___3___ separated by commas"
" between the parentheses. ___3___ can be standard data types such as string, number"
" ,dictionary, tuple, and ___4___ or can be more complicated such as ___5___"
" and ___6___ functions.")
list_of_answers_Programming = ["Functions", "procedures", "arguments", "lists", "objects", "lambda"]
blank_space = ["___1___", "___2___", "___3___", "___4___", "___5___", "___6___]"]
#List of levels with corresponding lives/guesses that player can have
quiz_list = ["Apple", "Bond", "Programming"]
level_list = ["easy", "medium", "hard", "superhard", "insane"]
lives_easy = 5
lives_medium = 4
lives_hard = 3
lives_superhard = 2
lives_insane = 1
def choose_quiz():
""" Prompts player to pick a type of quiz and loads the quiz """
#Input = player_quiz (raw input from player)
#Output = loaded quiz, player chose
while True:
player_quiz = raw_input("Please, select a quiz you want to play: "
"(Apple, Bond or Programming): ")
if player_quiz == "Apple":
return Apple_quiz
elif player_quiz == "Bond":
return Bond_quiz
elif player_quiz == "Programming":
return Programming_quiz
else:
print "We don't have such quiz, pick again!"
def answers_for_quiz():
""" Loads appropiate answers to the quiz that player has chosen"""
#Input = player quiz (raw input from player)
#Output = loaded quiz answers from the quiz player chose
player_quiz_pick = choose_quiz()
if player_quiz_pick == Apple_quiz:
return list_of_answers_Apple
elif player_quiz_pick == Bond_quiz:
return list_of_answers_Bond
elif player_quiz_pick == Programming_quiz:
return list_of_answers_Programming
def player_level():
""" Loads a difficulty that player chooses """
#Input = player_level_input (raw input of player choosing a difficulty)
#Output = corresponding number of lives:
#Easy = 5 lives, Medium = 4 lives
#Hard = 3 lives, Superhard = 2 lives
#Insane = 1 life
while True:
player_level_input = raw_input("Please type in a difficulty level: "
"(easy, medium, hard, superhard, insane): ")
if player_level_input == "easy":
return lives_easy #Easy = 5 lives
elif player_level_input == "medium":
return lives_medium #Medium = 4 lives
elif player_level_input == "hard":
return lives_hard #Hard = 3 lives
elif player_level_input == "superhard":
return lives_superhard #Superhard = 2 lives
elif player_level_input == "insane":
return lives_insane #Insane = 1 life
else:
print "We do not have such difficulty! Pick again!"
def correct_answer(player_answer, list_of_answers, answers_index):
""" Checks, whether the the answer from player matches with the answer list. """
#Input: player_answer (raw input that player enters in order to fill in the blank)
#Output: "Right answer!" or "Wrong! Try again!" this output will be later used in the game
if player_answer == list_of_answers[answers_index]:
return "Right answer!"
return "Wrong! Try again!"
def initialize_game():
"""Functions that sets up a game so we can play it """
player_quiz_pick, player_level_pick, list_of_answers = choose_quiz(), player_level(), answers_for_quiz()
print player_quiz_pick
print "\nYou will get maximum " + str(player_level_pick) + " guesses for this game. Good luck.\n"
blanks_index, answers_index, player_lives = 0, 0, 0
#for elements in blank_space:
while blanks_index < len(blank_space):
player_answer = raw_input("Please type in your answer for " + blank_space[blanks_index] + ": ")
if correct_answer(player_answer,list_of_answers,answers_index) == "Right answer!":
print "Correct answer! Keep going!\n"
player_quiz_pick = player_quiz_pick.replace(blank_space[blanks_index],player_answer)
answers_index += 1
blanks_index += 1
print player_quiz_pick
if blanks_index == len(blank_space):
print "Congratulations! You nailed it! You are the winner!"
else:
player_level_pick -= 1
if player_level_pick == 0:
print "Game over! Maybe next time!"
break
else:
print "One life less, that sucks! Have another shot!"
print "You have " + str(player_level_pick) + " guesses left."
initialize_game()
Your main problem is that you keep calling the same functions over and over again and do not save the input into variables. Here are some tips about your code and questions:
You are not doing anything with your player_level() method call, so the player doesn't actually chooses a level in a way that affects the game. You should change the function call, so the returned value will be stored.
//the call to the method:
player_level_pick = player_level()
Afterwards, you keep calling the player_level() method, and not using the actual answer that the user supplied. Change all player_level() appearences to player_level_pick - the variable you use to save the answer (as I showed above). Same goes to all other unneeded function calls such as choose_level().
You should initialize number_of_guesses, player_lives, list_of_answers, and other vars to a matching value to player_level_pick as well, so it will hold the right value according to the level. Likewise, you should change this line:
# the line that checks if game is over
# change from:
if number_of_guesses == player_lives:
# to :
if number_of_guesses == 0:
In order to return multiple values, you have to use tuples. Using multiple return statements one after the other does not work anywhere.
so, instead of:
return list_of_answers
return number_of_guesses
return blanks_index
return answers_index
return player_lives
you should use tuples, and unpack them properly:
# the return statement:
return (list_of_answers, number_of_guesses, blanks_index, answers_index, player_lives)
# and the unpacking in the calling function:
list_of_answers, number_of_guesses, blanks_index, answers_index, player_lives = initialize_game()
this way, all of the returned values go into the wanted variables in the calling function. this way, you need to call the initialize_game() from play_game(). it will be the efficient way for you.
Just saying it again, as I said in the end of (4) - you should unit initialize_game() and play_game() into a single function (because a lot of data is the same needed data), or just call initialize_game() from play_game().
Better practice then using this recursivly: return choose_level(), you should use a while True: loop, and just brake when you get a proper answer.

Categories

Resources