How do I loop an if statement until needed and then stop - python

I want to loop my driver code and, once done, ask the user if they want to convert another currency into MYR. Everytime through the loop, save the returnedamount to an array and, once the user has no more currencies, they need to convert. The program will add the varibles in the array together to produce the sum and print that. If required, turn that sum into another currency.
class Currency_convertor:
rates = {}
def __init__(self, url):
data = requests.get(url).json()
self.rates = data["rates"]
def convert(self, from_currency, to_currency, amount):
initial_amount = amount
if from_currency != 'EUR' :
amount = amount / self.rates[from_currency]
amount = round(amount * self.rates[to_currency], 2)
print('{} {} = {} {}'.format(initial_amount, from_currency, amount, to_currency))
return amount
Driver code
if __name__ == "__main__":
YOUR_ACCESS_KEY = ''
url = 'https://api.exchangerate-api.com/v4/latest/USD'
c = Currency_convertor(url)
from_country = input("From Country: ")
to_country = input("TO Country: ")
amount = int(input("Amount: "))
returnedamount=c.convert(from_country, to_country, amount)

Use a while statement.
Example:
x = 0
while x < 10:
# This will keep running until the condition is no longer True
print(x)
x += 1
# Then run any final stuff outside of the loop
print('Finished looping')

Use "While" Instead of "if"

Related

How to reduce repeated code with different variable names (python)

class Budget:
def __init__(self):
self.wants_perc = 0
self.wants_amt = 0
self.wants_left = 0
self.needs_perc = 0
self.needs_amt = 0
self.needs_left = 0
self.food_perc = 0
self.food_amt = 0
self.food_left = 0
while True:
try:
self.monthly_income = float(input("Enter your monthly income after taxes: "))
break
except ValueError:
print("Invalid Input : Please enter a number")
continue
while True:
print("Enter desired percentage of income spent for each category (do not include %): ")
try:
self.wants_perc = float(input("Wants: "))
self.needs_perc = float(input("Needs: "))
self.food_perc = float(input("Food: "))
if self.wants_perc + self.needs_perc + self.food_perc not in range(95, 105):
print("Invalid Input : Must add to 100%")
continue
else:
break
except ValueError:
print("Invalid Input : Please enter a number")
continue
def deposit(self):
dep_loc = input("Where would you like to deposit? ")
while True:
try:
if dep_loc.lower() == "wants":
self.wdep_amt = float(input("Deposit amount: "))
self.wants()
break
elif dep_loc.lower() == "needs":
self.ndep_amt = float(input("Deposit amount: "))
self.needs()
break
elif dep_loc.lower() == "food":
self.fdep_amt = float(input("Deposit amount: "))
self.food()
break
else:
print("Invalid Input")
break
except ValueError:
print("Invalid Input : Please enter a number")
continue
def wants(self):
self.wants_max = (self.wants_perc / 100) * self.monthly_income
self.wants_amt += self.wdep_amt
self.wants_left = self.wants_max - self.wants_amt
print(f"Amount spent on wants: ${self.wants_amt} \nAmount left to spend: ${round(self.wants_left,2)}")
def needs(self):
self.needs_max = (self.needs_perc / 100) * self.monthly_income
self.needs_amt += self.ndep_amt
self.needs_left = self.needs_max - self.needs_amt
print(f"Amount spent on needs: ${self.needs_amt} \nAmount left to spend: ${round(self.needs_left,2)}")
def food(self):
self.food_max = (self.food_perc / 100) * self.monthly_income
self.food_amt += self.fdep_amt
self.food_left = self.food_max - self.food_amt
print(f"Amount spent on food: ${self.food_amt} \nAmount left to spend: ${round(self.food_left,2)}")
wyatt = Budget()
while True:
wyatt.deposit()
I know this is a very general question, but is it possible to reduce the amount of repeated code I use? I feel like there has to be a way to use one general variable in a loop for each of the categories. My three functions that use the food, wants, and needs variables are all the exact same besides the names. I thought of getting user input and adding it to a list and indexing that list to get each category, but I couldn't fully figure it out. This may be too broad for stack overflow and if it is I apologize. Thanks!
In general there is no mechanism for reducing the amount of code - if there was, it would already be part of the language. Making a dictionary instead of member variables doesn't really help, because all it will do is replace your 9 member variables with 9 dictionary items.
However, there is an opportunity for factoring out repeated operations. Your instinct is correct that repeated blocks of code are a sign of poor design. I would suggest you start with a class structure something like this:
class BudgetItem:
def __init__(self, name):
self.name = name
self.perc = 0
self.amt = 0
self.left = 0
def get_perc(self):
self.perc = float(input(f"{self.name}: "))
class Budget:
def __init__(self, monthly_income):
self.monthly_income = monthly_income
self.wants = BudgetItem("Wants")
self.needs = BudgetItem("Needs")
self.food = BudgetItem("Food")
self.all_items = (self.wants, self.needs, self.food)
def gather_percentages(self):
print("Enter desired percentage of income"
" spent for each category (do not include %): ")
for b in self.all_items:
b.get_perc()
if 95.0 <= sum(b.perc for b in self.all_items) <= 105.0:
print("Precentages must sum to 100")
# etc.
Create a separate class to represent a budget category, since the logic for each is identical. Add methods to the little class to capture that logic. Now re-write your main class in terms of those three individual items. I won't take the time to refactor your whole program, but I hope you get the idea. You should end up with a much shorter program and no significant repeated logic.
One other thing: I think that putting an "input" statement in a class constructor is a terrible idea. Constructors should not contain complicated loops or extended logic. I would put it outside the class and pass the data into the class as arguments, or as method calls.

Python script not producing output

I have been tasked with reading values inputted by a user(using a while loop) to then store them in a list/array whilst using try: except: to determine if a given input is invalid. In continuation, if the user inputs "done" as a value it will break the loop and print() the total, sum, and average of all the imputed values.
I have gotten this snippet so far:
class Input:
def __init__(self, number_input_value, total_to_be_calculated, main_value):
self.number_input_value = 0
self.total_to_be_calculated = 0.0
self.main_value = input('Enter A Number: ')
self.number_input_value1 = float(self.main_value)
def loop_get_inputs(self):
while True:
self.main_value
if self.main_value == 'done':
break
try :
self.number_input_value1
except :
print('INVAL["VAL"]')
continue
self.number_input_value = self.number_input_value1
self.total_to_be_calculated = self.total_to_be_calculated + self.number_input_value1
print ("Finished successfully!")
print (
self.total_to_be_calculated,
self.number_input_value,
self.total_to_be_calculated/self.number_input_value
)
if __name__ in '__main__':
Input
I have no clue what's wrong, because when it runs it outputs nothing.
Output:
>>>
You need create an instance of the class 'Input' and call the method:
##(self, number_input_value, total_to_be_calculated, main_value)
inp = Input(100, 1000, 10)
#call the method
inp.loop_get_inputs()
Basically:
1 - You have to initialize your class/object before using it.
2 - Having code on the construct is not recommend. You should call a public method of the class to start the "process".
3 - That try-except wasn't doing much. You can, for example, surround the string (from input()) cast to float and print INVALID if the input can't be casted.
4 - You can use += to simplify a = a + b
5 - lower() will convert user input to lowercase, meaning that DONE, done and DoNe (etc) will be considered as "quit" input.
Does this make sense?
class Input:
def __init__(self):
self.number_inputs = 0
self.total = 0.0
def run(self):
self.__get_user_values()
print(f"total: '{self.total}'")
print(f"number_inputs: '{self.number_inputs}'")
print(f"average: '{self.total / self.number_inputs}'")
def __get_user_values(self):
while True:
value = input('Enter A Number: ')
if value.lower() == 'done':
break
if self.__is_valid_input(value):
self.total += float(value)
self.number_inputs += 1
def __is_valid_input(self, value) -> bool:
try:
float(value)
return True
except ValueError:
print('INVAL["VAL"]')
return False
if __name__ in '__main__':
input_wrapper = Input()
input_wrapper.run()

Is the example below considered efficient? And if not, how so can it be better?

I am new to programming and object-oriented programming.
Below is a portion of the code in python that is running just fine as intended. I have hard-coded some variable for testing purposes at the open_bank_account().
Question: Would be considered fairly optimal and efficient? If not, where can I look to improve the code?
class Bank_Account:
def __init__(self, account_id, account_pin, account_balance):
self._account_id = account_id
self._account_pin = account_pin
self._account_balance = account_balance
self._individual_bank_account_dicitionary = {}
self._individual_bank_account_dicitionary[account_id] = {"Pin": account_pin, "Balance": account_balance}
def get_bank_account_balance(self, account_id):
return "Balance: ${:.2f}".format(self._individual_bank_account_dicitionary[account_id]["Balance"])
def __str__(self):
return "{}".format(self._individual_bank_account_dicitionary)
class Bank:
def __init__(self, bank_name):
self._bank_name = bank_name
self._bank_dicitionary = {}
def update_bank_dictionary(self, bank_account):
self._bank_dicitionary[bank_account._account_id] = {"Pin": bank_account._account_pin, "Balance": bank_account._account_balance}
# 1. A method to return the dictionary of bank accounts of the object from class Bank.
# 2. In this case, only bank_1 from main() is the object argument.
def get_bank_dictionary(self):
return self._bank_dicitionary
# 1. Method to create object bank_account only when needed.
def get_bank_account(self, account_id):
account_pin = self._bank_dicitionary[account_id]["Pin"]
account_balance = self._bank_dicitionary[account_id]["Balance"]
bank_account = Bank_Account(account_id, account_pin, account_balance)
return bank_account
# 1. This is used to convert the dictionary into a string for printing purposes.
def string_bank_dictionary(self):
string_list = ["account ID: {} \naccount Pin: {} \nBank Balance: {} \n".format(key, self._bank_dicitionary[key]["Pin"], self._bank_dicitionary[key]["Balance"])\
for key, value in self._bank_dicitionary.items()]
return "\n".join(string_list)
def __str__(self):
return "{}".format(self.string_bank_dictionary())
def open_bank_account(bank):
# # Uncomment out when running actual program.
# account_id = input("Enter account id here: ")
# account_pin = input("Enter account pin here: ")
# account_balance = input("Enter account initial balance here: ")
# Comment out when running actual program.
# Currently in used for testing purposes.
account_id = 455
account_pin = 123
account_balance = 888
bank_account = Bank_Account(account_id, account_pin, account_balance)
bank.update_bank_dictionary(bank_account)
# Comment out when running actual program.
# Currently in used for testing purposes.
account_id = 777
account_pin = 777
account_balance = 1
bank_account = Bank_Account(account_id, account_pin, account_balance)
bank.update_bank_dictionary(bank_account)
# Comment out when running actual program.
# Currently in used for testing purposes.
account_id = 631
account_pin = 222
account_balance = 50
bank_account = Bank_Account(account_id, account_pin, account_balance)
bank.update_bank_dictionary(bank_account)
return bank
def check_bank_blanance(bank):
valid_id_password = False
temporary_dictionary = bank.get_bank_dictionary()
while True:
account_id = int(input("Enter account id here: "))
account_pin = int(input("Enter account pin here: "))
for key in temporary_dictionary.keys():
if account_id == key and temporary_dictionary[account_id]["Pin"] == account_pin:
valid_id_password = True
bank_account = bank.get_bank_account(account_id)
print(bank_account.get_bank_account_balance(account_id))
break
if valid_id_password == True:
break
else:
print("Invalid account id/password. Please try again.")
def main():
bank_1 = Bank("ABC Bank")
while True:
print("Menu \n1. Open bank account \n2. Check balance")
while True:
account_choice = int(input("Enter option here: "))
if account_choice <= 0 and account_choice >= 7:
account_choice = int(input("Enter option here: "))
else:
break
if account_choice == 6:
break
elif account_choice == 1:
bank_1 = open_bank_account(bank_1)
elif account_choice == 2:
balance = check_bank_blanance(bank_1)
main()
The program works just fine. I would like to seek pointers on improvement if I code this better and more efficiently.
I have designed and kept only one object in the main(); i.e. bank_1; this contains a dictionary of the multiple bank account information. I have elected to only create the object bank_account at the open_bank_account() and check_bank_blanance() only when needed and these objects disappear once the function is done.
The intention here is to keep as little objects available as possible at the main().
No errors encountered. The program runs just fine; just enter <1>, then enter <2>, then enter <777> followed by <777>. It will print the bank account balance of $1.00 of the account id 777.

Cannot pass returned values from function to another function in python

My goal is to have a small program which checks if a customer is approved for a bank loan. It requires the customer to earn > 30k per year and to have atleast 2 years of experience on his/her current job. The values are get via user input. I implemented regexs to validate the input to be only digits without any strigns or negatives, nor 0.
But the 3rd function asses_customer is always executing the else part. I think everytime the parameters are either None, either 0
here's the source code:
import sys
import re
import logging
import self as self
class loan_qualifier():
# This program determines whether a bank customer
# qualifies for a loan.
def __init__(self): #creates object
pass
def main():
salary_check()
work_exp_check()
asses_customer(salary = 0, years_on_job = 0)
def salary_check():
input_counter = 0 # local variable
# Get the customer's annual salary.
salary = raw_input('Enter your annual salary: ')
salary = re.match(r"(?<![-.])\b[1-9][0-9]*\b", salary)
while not salary:
salary = raw_input('Wrong value. Enter again: ')
salary = re.match(r"(?<![-.])\b[1-9][0-9]*\b", salary)
input_counter += 1
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
else:
return salary
def work_exp_check():
input_counter = 0 #local variable to this function
# Get the number of years on the current job.
years_on_job = raw_input('Enter the number of ' +
'years on your current job: ')
years_on_job = re.match(r"(?<![-.])\b[1-9][0-9]*\b", years_on_job)
while not years_on_job:
years_on_job = raw_input('Wrong work experience. Enter again: ')
years_on_job = re.match(r"(?<![-.])\b[1-9][0-9]*\b", years_on_job)
input_counter += 1
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
else:
return years_on_job
def asses_customer(salary, years_on_job):
# Determine whether the customer qualifies.
if salary >= 30000.0 or years_on_job >= 2:
print 'You qualify for the loan. '
else:
print 'You do not qualify for this loan. '
# Call main()
main()
You have stated:
It requires the customer to earn > 30k per year and to have at least 2 years of experience on his/her current job.
We can write some simple statements that request a number and if a number is not given then ask for that number again.
The following code is a very simple approach to achieving that goal.
class Loan_Checker():
def __init__(self):
self.salary = 0
self.years_on_job = 0
self.request_salary()
self.request_years()
self.check_if_qualified()
def request_salary(self):
x = raw_input('Enter your annual salary: ')
try:
self.salary = int(x)
except:
print("Please enter a valid number")
self.request_salary()
def request_years(self):
x = raw_input('Enter the number of years on your current job: ')
try:
self.years_on_job = int(x)
except:
print("Please enter a valid number")
self.request_years()
def check_if_qualified(self):
if self.salary >= 30000 and self.years_on_job >= 2:
print 'You qualify for the loan. '
else:
print 'You do not qualify for this loan. '
Loan_Checker()
You have a few errors in your code, and I've refactored it to use the class structure you seemed to want to imply.
import sys
import re
import logging
class loan_qualifier():
# This program determines whether a bank customer
# qualifies for a loan.
def __init__(self): #creates object
self.salary = self.salary_check()
self.years_on_job = self.work_exp_check()
def salary_check(self):
input_counter = 0 # local variable
# Get the customer's annual salary.
salary = None
while salary is None:
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
elif input_counter >= 1:
print ("Invalid salary.")
salary = raw_input('Enter your salary: ')
salary = re.match(r"(?<![-.])\b[1-9][0-9]*\b", salary).group(0)
input_counter += 1
# broke out of loop, so valid salary
return salary
def work_exp_check(self):
input_counter = 0 #local variable to this function
# Get the number of years on the current job.
years_on_job = None
while years_on_job is None:
if input_counter >= 6:
print ("No more tries! No loan!")
sys.exit(0)
elif input_counter >= 1:
print ("Invalid year amount")
years_on_job = raw_input('Enter the number of years at your current job: ')
years_on_job = re.match(r"(?<![-.])\b[1-9][0-9]*\b", years_on_job).group(0)
input_counter += 1
# broke out of loop, so valid years_on_job
return years_on_job
def assess_customer(self):
# Determine whether the customer qualifies.
if int(self.salary) >= 30000.0 and int(self.years_on_job) >= 2:
print 'You qualify for the loan. '
else:
print 'You do not qualify for this loan. '
if __name__ == "__main__":
lq = loan_qualifier()
lq.assess_customer()
Some of the errors fixed include the way you were calling assess_customer initially (you were assigning 0's to both values in the function call), as well as the spelling of assess :p. Your condition in assess_customer should also have been an and instead of an or (you wanted both conditions to be true for them to qualify, not for either condition to be true).
You actually don't even really need to do the:
self.salary = self.salary_check()
self.years_on_job = self.work_exp_check()
lines. You could just directly assign the class variables in the functions (i.e. instead of returning, just set self.salary = blah in salary_check). That's kind of a personal choice thing though. I think this makes it clear.
Hopefully this is all clear to you. Let me know if you have any questions. The code can be called by simply typing python NAME_OF_YOUR_FILE.py.
Edit: I didn't realize how broken the salary and years checks were, the new code should fix them.
Edit: Fixed the regex results in this version. My bad.
In this fragment you pass third function always salary = 0 and years_on_job = 0
Try this way:
salary = salary_check()
years_on_job = work_exp_check()
asses_customer(salary, years_on_job)

While loop not ending

def getStocks():
stockNames = []
stockPrices = []
done = 0
while done != 1:
stock = input('Enter Stock symbol: ')
if stock == 'done':
done = 1
else:
price = int(input('Enter Price of Stock: '))
print("")
stockNames.append(stock)
stockPrices.append(price)
return stockNames, stockPrices
The issue is that "Enter Stock symbol: " appears even after the user types 'done', how can I get the infinite loop to terminate at this point? I tried using break but it did not provide the results I was looking for
instead of input use raw_input it will fix the problem
def getStocks():
stockNames = []
stockPrices = []
done = 0
while done != 1:
stock = raw_input('Enter Stock symbol: ')
if stock == 'done':
done = 1
else:
price = int(input('Enter Price of Stock: '))
print("")
stockNames.append(stock)
stockPrices.append(price)
return stockNames, stockPrices
python version: 2.7+
you probably want raw_input(), as input() will actually try to evaluate the expression it gets back.

Categories

Resources