I created two programs, one is an ATM simulator and other is a Virtual Doctor which reads data from excel sheet and on the basis of user input, tells what disease the user might be suffering from.
now I want to connect the atm to virtual doctor such that it withdraws the amount of medicines from the bank account
I imported atm to virtual doctor but the functions don't seem to be working, they do nothing when called and the process exits.
#code for ATM
userpin = ["1234", "2345", "3456", "4567"]
userpass = ["1234", "2345", "3456", "4567"]
username = ["Rishabh", "Siddharth", "Kashish", "Mahima"]
userbalance = [20500, 43567, 45672, 67800]
class Bank:
def __init__(self, bal=0, index=0):
#if __name__ == '__main__':
self.bal = bal
self.index = index
def start(self):
if __name__ == '__main__':
print("\t\t=== Welcome to ATM ===")
inputpin=input("Enter your pin :")
inputpass= input("Enter your password :")
b1.pinpasscheck(inputpin,inputpass)
def pinpasscheck(self,pin,passw):
self.pin=pin
self.passw=passw
inputpin=pin
inputpass=passw
index=0
flag= False
for i in range(0,len(userpin)):
if inputpin==userpin[i]:
index=i
print(index)
if inputpass==userpass[index]:
print("Login Succeeded !")
flag= True
b1.operationlist(index)
if flag==False:
print("Login invalid. Please check username or password")
else:
pass
else:
pass
def operationlist(self,indexval):
self.indexval=indexval
index=indexval
print("\n Hello, ", username[index])
print("""
1) Balance
2) Withdraw
3) Deposit
4) Change password
5) Quit
""")
useroption = int(input("Select an option:"))
if useroption == 1:
print("\nYour current balance is {}".format(userbalance[index]))
b1.operationlist(index)
elif useroption == 2:
amount= int(input("\nEnter amount you want you want to withdraw : Rs"))
b1.withdraw(amount,index)
else:
print("None of the above options selected. Please select any one of the provided options.")
b1.operationlist(index)
def withdraw(self, amt, index):
self.amt= amt
amount = amt
self.index= index
if amount > userbalance[index]:
print("Oops! Insufficient funds.")
b1.operationlist(index)
rembalance = userbalance[index] - amount
userbalance.remove(userbalance[index])
userbalance.insert(index, rembalance)
print("Your remaining balance is: ", userbalance[index])
b1.operationlist(index)
b1 = Bank()
b1.start()
#code for VirtualDoctor
import xlrd
import pandas
from NewATM import Bank
path = "symptoms.xlsx"
book = xlrd.open_workbook(path)
sheet= book.sheet_by_index(0)
b2= Bank()
data= [[sheet.cell_value(r,c) for c in range (sheet.ncols)] for r in range (sheet.nrows)]
diseaselist= []
for i in range (1,sheet.nrows):
diseaselist.append(sheet.cell_value(i,0))
symptoms=[]
for i in range (1, data.__len__()):
tmp= data[i][1:5]
symptoms.append(tmp)
print(symptoms)
inputlist = []
b2.start() #THIS DOES NOT WORKK !!!!!!!!!!!!!!!!!!!!! WHY ???
The virtual doctor program should now go to the atm and then I can move forward with my code, but this doesn't seem to be working.
Your problem is that the code from your ATM class requires data which is set as global variables in the class itself. In terms of OOP, this is bad practice and in your particular case the code just won’t work as the variables are out of scope to the main (virtual doctor).
Either move those variables into the class itself (which is still bad practice) or keep them elsewhere and import the matrix of data when calling the class, and pass it to each individual functions.
Lastly you are creating an instance of bank called b1 to use in the class, which doesn’t make sense in terms of OOP. Change the b1 to self such that your calling the functions like self.function (one edit is changing b1.pinpasscheck() to self.pinpasscheck()).
Related
Pretty new to coding, sorry.
I'm writing a little text adventure, and attempting to add save/load functionality. I've included all my testing code I'm putting together for context. Hope it's not too much.
I have a series of nested functions to access the save and load functions. (In code: game>menu>choices 3,4). Saving and loading is giving me issues.
Error Messages:
For saving I'm getting an error: local variable 'cubicles' referenced before assignment.
For loading I'm getting an error: shadows name 'cubicles' from outer scope.
I suspect the issue is I'm creating a local variable within the nested function even though what I'm actually trying to do is alter a global. Is the proper way to fix this to simply write 'global' before the objects I'm loading?
Happy to take any other helpful criticism on the way I've written my code btw. Thanks.
(Edited Code for brevity - sorry I couldn't get it shorter.)
import pickle
class Room:
def __init__(self, state, name, desc):
self.state = state
self.name = name
self.desc = desc
def enter(self):
print("\n{}".format(self.name).upper())
print(self.desc)
print("Current room state: {}".format(self.state))
cubicles = Room(0, "your cubicle", "It's a room full of cubicles. You can go to Marcia's Office or your Boss's Office.")
marciaOffice = Room(0, "Marcia's office", "It's a small office where Marcia works. You can go to the cubicles or your Boss's Office.")
bossOffice = Room(0, "your Boss's office", "This is where your boss works. You can go to the cubicles or Marcia's Office.")
currentRoom = cubicles
print("You are in your cubicle")
def game():
global currentRoom
def decisionTree():
print("What do you do?")
response = input(">").lower()
if ("advance" and "all") in response:
advanceAll(response)
elif ("menu" or "pause") in response:
menu()
else:
print("Invalid response. Try going to another room or advancing the room state.")
def advanceAll(response):
if ("advance" and "all") in response:
cubicles.state = 3
marciaOffice.state = 7
bossOffice.state = 9
print("All rooms advanced to 3, 9, and 7.")
game()
def menu():
print("MENU:")
print("1. Return to Game")
print("2. Quit")
print("3. Save")
print("4. Load")
response = input(">")
if "1" in response:
game()
elif "2" in response:
quit()
elif "3" in response:
with open('save_game.pkl', 'wb') as save_game:
pickle.dump(cubicles, save_game)
pickle.dump(marciaOffice, save_game)
pickle.dump(bossOffice, save_game)
menu()
elif "4" in response:
with open('save_game.pkl', 'rb') as load_game:
cubicles = pickle.load(load_game)
marciaOffice = pickle.load(load_game)
bossOffice = pickle.load(load_game)
print("States are as follows:")
print("Cubicles:{}".format(cubicles.state))
print("Marcia's Office:{}".format(marciaOffice.state))
print("Boss's Office:{}".format(bossOffice.state))
menu()
else:
print("Unknown command")
decisionTree()
game()
I am building a budget program, and I am new to python,a month into it. I started this project in class to push myself. Well I haven't taken a database class yet and we only briefly touch on it. The issue I am having is when I am passing a tuple to sqlite3 to put the values into the corresponding fields. I have 2 files. The functions file, that is only for the functions not relating to direct database manipulation. The other file contains all the functions for database creation to manipulation.
Here is the code that is giving me problems
import budget_buddy
total_money = 0
def deposits():
"""Deposits function so we can call it later on"""
return float(input('Please enter deposit amount:'))
def input_expense_item() -> tuple:
"""
Prompt the user to enter an expense type, and the amount for the expense
:return: Tuple - expense type, amount
"""
expense_type = input("What is the expense item?\n").capitalize()
cost = None
# must ensure that the user provides a valid number! In this case, a valid decimal!
while not cost:
temp = input(f"How much was '{expense_type}'?\n")
try:
cost = float(temp)
except ValueError:
print(f"{temp} - was an invalid entry. Please make sure you entered a valid number")
# This is how to return a tuple. This means you can assign two variables when calling this function as seen below
return expense_type, cost
#def balance(expense_amount: int):
#"""Balance function to be used later on as well"""
#return total_money - expense_amount
def cash_on_hand():
"""
Cash_on_hand function, this is asking how much money not in bank
accounts do you have.
"""
return float(input('How much money do you have on hand:'))
while True:
menu_option = input("What option do you want to do?\n"
"1: Enter deposit\n"
"2: Enter cash on hand\n"
"3: Enter expenses\n"
"4: Monthly Deposit Total\n")
if menu_option == "1":
deposit_amount = deposits()
#total_money += deposit_amount
budget_buddy.insert_deposits(deposit_amount)
elif menu_option == "2":
cash_amount = cash_on_hand()
#total_money += cash_amount
budget_buddy.insert_cash(cash_amount)
elif menu_option == "3":
#new_expense_type, new_expense_amount = input_expense_item()
#print(f"The user wants to add {new_expense_type} for ${new_expense_amount}")
expense_type, cost = input_expense_item()
budget_buddy.insert_expenses(input_expense_item)
#Code below was used previously, attempting changes but keeping the code just in case for a fall back
#current_balance = balance(new_expense_amount) + cash_on_hand()
#total_money = current_balance
#print(f"Total balance is ${total_money}")
elif menu_option == "4":
budget_buddy.monthly_deposit_total()
Please ignore the comments, this code has been changed a lot since making the start of the program. And I am actively changing the way I do it.
The next is my database code,
# Importing OS module to determine desktop path
import os
import sqlite3
from datetime import datetime
from sqlite3 import Error
"""Current month with %B argument,which displays entire month name"""
current_month = datetime.now().strftime('%B')
"""Current time in year-month-day. Followed by Hour:Minute.
Used to track when data was entered.
Not used as of yet on 2020-10-17, but will be as the program develops."""
current_time = datetime.now().strftime('%Y-%m-%d')
current_time_iso = datetime.now().isoformat(sep=' ',timespec='minutes')
"""Using os module to determine the current users desktop path so we can
make the budget database file on the desktop so it is easier to find.
Sqlite3 module and Error module as well to create a connection to the
database after it is made, returning error (e) if the database does not exist."""
desktop = os.path.join(os.path.join(os.environ["USERPROFILE"]), "Desktop")
default_path = os.path.join(desktop, "budget.db")
if os.path.exists(default_path):
print('Database already exists\n')
pass
else:
print(f'Creating database budget.db at {desktop}')
pass
def sql_connection(db_file):
conn = None
try:
conn = sqlite3.connect(db_file)
print('Connected succsefully to budget.db using Sqlite3 version {}!'.format(sqlite3.version))
return conn
except Error as e:
print(e)
finally:
if not conn:
conn.close()
def monthly_table(conn):
cursorObj = conn.cursor()
cursorObj.execute(f"CREATE TABLE IF NOT EXISTS {current_month} (Deposit float, Deposit_Date real, Expense_Amount float, Expense_Type text, Cash_on_Hand float, Balance float)")
conn.commit()
print(f'Table {current_month} successfully created in budget.db')
conn = sql_connection(default_path)
if conn:
monthly_table(conn)
else:
print('Exiting')
def insert_deposits(amt):
insert_command_amt = """insert into {} (Deposit, Deposit_Date) values (?,?)""".format(current_month)
insert_amount = amt
insert_timestamp = current_time_iso
multi_insert_date_amount = insert_amount, insert_timestamp
conn.execute(insert_command_amt, multi_insert_date_amount)
conn.execute("commit;")
def monthly_deposit_total():
# mdt = monthly deposit total
mdt_query = """Select (Deposit) From {}""".format(current_month)
cursor = conn.cursor()
cursor.execute(mdt_query)
total = 0
for row in cursor:
total += row[0]
print(f"Your total deposits this month is: ${total}")
def insert_expenses(text,amt):
insert_expense_command = """insert into {} (Expense_Type, Expense_Amount) values (?,?)""".format(current_month)
insert_expense_name = str()
insert_expense_amt = amt
multi_expense_insert = insert_expense_name, insert_expense_amt
conn.execute(insert_expense_command, multi_expense_insert)
conn.execute("commit;")
My issue is the last function here,
def insert_expenses(text,amt):
insert_expense_command = """insert into {} (Expense_Type, Expense_Amount) values (?,?)""".format(current_month)
insert_expense_name = str()
insert_expense_amt = amt
multi_expense_insert = insert_expense_name, insert_expense_amt
conn.execute(insert_expense_command, multi_expense_insert)
conn.execute("commit;")
which is used by the input_expense_item function in the first code block which is my functions file.
I have been pouring over the code to find my error causing the issue but I cannot find it.
I understand it may not make sense to others why I am doing seperate tables in the database but it is how it will be done, that is not changing because I have plans for it.
The exact error I am getting is this
File "F:\Documents\GitHub\Budget_buddy\functions_for_BB.py", line
80, in
budget_buddy.insert_expenses(input_expense_item)
TypeError: insert_expenses() missing 1 required positional argument:
'amt'**
The program works as intended up until it tries to push the values to the database for the expense command.
input_expense_items returns a tuple, which is one "object", therefore, nothing is being sent to amt when insert_expenses is called. The tuple represents the exact object needed for the placeholder argument to execute. If insert_expenses takes one argument, the parsing steps can be eliminated and the argument variable will be the second arg to execute.
Okay so I finally got it fixed thank to some help. Here is what I did to get it to work as intended.
import budget_buddy
def deposits():
"""Deposits function so we can call it later on"""
return float(input('Please enter deposit amount:'))
def input_expense_item() -> tuple:
"""
Prompt the user to enter an expense type, and the amount for the expense
:return: Tuple - expense type, amount
"""
expense_type = input("What is the expense item?\n").capitalize()
cost = None
# must ensure that the user provides a valid number! In this case, a valid decimal!
while not cost:
temp = input(f"How much was '{expense_type}'?\n")
try:
cost = float(temp)
except ValueError:
print(f"{temp} - was an invalid entry. Please make sure you entered a valid number\n")
print(f'User wants to add {expense_type} for ${cost}\n')
return expense_type, cost
def cash_on_hand():
"""
Cash_on_hand function, this is asking how much money not in bank
accounts do you have.
"""
return float(input('How much money do you have on hand:'))
while True:
menu_option = input("What option do you want to do?\n"
"1: Enter deposit\n"
"2: Enter Expenses\n"
"3: Monthly Deposits Total\n"
"4: Monthly Balance\n\n")
if menu_option == "1":
deposit_amount = deposits()
budget_buddy.insert_deposits(deposit_amount)
elif menu_option == "2":
budget_buddy.insert_expenses(*input_expense_item())
elif menu_option == "3":
budget_buddy.monthly_deposit_total()
elif menu_option == "4":
#this command will take the deposits, subtract expenses and ask user if they want to add cash on hand
print('Command not implimented yet, please try again later')
below is what changed in the functions file, I unpacked the tuple in place(?) while calling the function to be used and it passes the tuple values on over
elif menu_option == "2":
budget_buddy.insert_expenses(*input_expense_item())
As you can see below where it uses the values.
def insert_expenses(expense_type, cost):
insert_expense_command = """insert into {} (Expense_Type, Expense_Amount) values (?,?)""".format(current_month)
insert_expense_name = expense_type
insert_expense_amt = cost
multi_expense_insert = insert_expense_name, insert_expense_amt
conn.execute(insert_expense_command, multi_expense_insert)
conn.execute("commit;")
so my classes won't recognize each other but when left to work alone they do work as seen in the consult printing at the bottom of the post. However the deposit and transfer are popping up the ram location, however, they do work fine when done separately just as shown in the consult action in the bottom part.
<function cashier.deposit at 0x0000023A9B656048>
import datetime
now = datetime.datetime.now()
class account:
owner = "name"
pin = "1823"
balance = 800
def __init__(self, transfer, withdraw, deposit, consult):
self.transfer = transfer
self.withdraw = withdraw
self.deposit = deposit
self.consult = consult
class cashier:
def __init__(self, withdraw, deposit, transfer, consult):
self.transfer = transfer
self.consult = consult
self.withdraw = withdraw
self.deposit = deposit
def deposit(self):
print("Please type pin to proceed")
if account.pin == 1823:
print("who would you like to send money to?")
else:
print("Invalid pin")
def transfer(self):
pass
def withdraw(self):
withdrawal = input("How much money do you want to withdraw? (there is a limit up to 10,000$ a day!)")
account.balance -= int(withdrawal)
if int(withdrawal) > 10000:
print("withdrawals cannot be larger than 10,000 a day!")
exit()
elif int(withdrawal) > account.balance:
print("your account does not have enough funds to complete your transaction")
else:
print("Transaction succesfull!\nPlease collect your money")
print('Today is', now)
print("Hello %s!\nWhat can I do for you today?" % account.owner)
action = input("Use commands such as withdraw, deposit, transfer or consult to continue!\n")
if action == "withdraw":
print(cashier.withdraw)
if action == "consult":
print("Your account's balance is %s $" % str(account.balance))
if action == "transfer":
print(cashier.transfer)
if action == "deposit":
print(cashier.deposit)
else:
print("Uknown command, exiting programm")
exit()
The various functions of cashier do not return anything, so the prints are just printing the string representation of the function. You could have the functions return a string like so:
class Cashier: # PEP8 calls for CamelCase here
def deposit(self):
pin = input("Please type pin to proceed")
if Account.pin == pin:
return "who would you like to send money to?"
else:
return "Invalid pin"
def transfer(self):
pass
def withdraw(self):
withdrawal = input("How much money do you want to withdraw? (there is a limit up to 10,000$ a day!)")
Account.balance -= int(withdrawal)
if int(withdrawal) > 10000:
return "withdrawals cannot be larger than 10,000 a day!"
elif int(withdrawal) > Account.balance:
return "your Account does not have enough funds to complete your transaction"
else:
return "Transaction successful!\nPlease collect your money"
Edit: I removed the initializer, as these weren't doing anything. You need to instantiate your cashier with cashier = Cashier(), then call the functions of Cashier with cashier.withdraw().
There's a fundamental misunderstanding on how classes work here (and OOP in general). You should read through the Python docs on building classes before you go any further.
To use your classes, you need to instantate them like this
Cashier = cashier()//I don't think you should ask for the transfer details while instantiating. But you can do that by adding the parameter in the bracket
Now you can use the functions on the Cashier variable like:-
Cashier.deposit(deposit_money)
I think if you don't want to instantiate and want a function which does not actually store data, you can use a static function but I don't think that is what you want to do
I am working on a bank account program where the user logs in with a four digit number (pin).
I want to find a way to access a specific object with all its attributes at runtime after the right pin has been entered.
class Konto(object):
def __init__(self, account_holder, balance , pin):
self.account_holder = account_holder
self.balance = balance
self.pin = pin
I have three different objects defined in a list
kontoList = []
kontoList.append(Konto("Person1", 143541, 1223)),
kontoList.append(Konto("Person2", 6230, 1234)),
kontoList.append(Konto("Person3", 4578, 4321))
The last attribute is the Pin that is entered by the user. When the program checks the pin is '1234' for example it displays a menu where you can get the current balance, account holder etc. In this case it would be 6230 (balance) and Person2 (account holder). So here is some code:
pin = input("PIN: ")
for konto in kontoList:
if konto.pin == pin:
print("Valid PIN")
continue
else:
print("not valid")
break
while True:
print("1: Withdrawal \n"
"2: Deposit \n"
"3: Transfer \n"
"4: Current Balance \n"
"5: Account Holder \n"
"6: Quit \n")`
choice = input("Your Choice: ")
Is there any way to access the specific object during runtime and then go on to work with it? I've looked up getattr() but it does not seem useful in this situation.
You could simply create a list of pins, then check whether the pin you're checking is contained in that list:
kontoPinList = [konto.pin for konto in kontoList]
and then you would check whether your pin is in the kontoPinList with:
pin in kontoPinList
EDIT: If you want to keep working with the konto you do the following:
for konto in kontoList:
if konto.pin == pin:
#do something with the konto here
EDIT nr.2: If you wish to now call functions on the konto, such as account_holder(), you just do account_holder(konto) and that should work.
The reason my first response was to write a getPin() function is because while this will not solve your problem, it is a good idea to "protect" your variables by deciding how you want to return them. (it's more of a java thing than a python thing)
However, as you pointed out, it is a useless function if all you're interested in is simply returning konto.pin .
You could try something like this:
kontos_with_pin = filter((lambda k: k.pin == pin), kontoList)
if len(kontos_with_pin) == 1:
relevant_konto = kontos_with_pin[0]
# Do something with relevant_konto
else:
# handle case where there is no konto with that pin, or more than one, etc.
I'm writing a program to simulate a bank scenario. It allows users (once they have logged in) to display their balance, withdraw and deposit money, and will eventually contain a transfer subroutine.
My problem is the login subroutine. I am having trouble getting my code to loop through both accounts in the tuple that saves them. I can log in to the first account and perform all the code's functions with that account but when I try to access the second account, I get the error message telling me that the account is not found. I am very certain that this is to do with the way I have written my loop but I cannot figure out how to fix it.
If someone could provide me with a solution that I can use to fix this error then I would be very grateful. If it is possible, could the solution also stick to the general format of my code and not be one where I have to create new functions and change the entire body of my LogOn function?
Here is the code:
accounts=[
["Luke",'00001','1234',1337],
["Louis",'00002','4321',420],
]
name = ""
x = []
def LogOn():
global name
global x
print ("Welcome to the Bank of Bailey")
accnum = raw_input("-please enter your account number-")
if len(accnum) != 5:
print("That number is not valid, please enter a valid number")
LogOn()
else:
for x in range(0,len(accounts)):
if accnum in accounts[x][1]:
name = accounts[x][0]
print ("Account found")
pin = raw_input("-please enter your pin-")
if pin in accounts[x]:
print ("Pin found")
MainMenu()
else:
print("Pin not found")
print("Please try again")
LogOn()
break
else:
print("Account not found")
print("Please try again")
LogOn()
The problem is:
if accnum in accounts[x][1]:
do something
else:
print("Account not found")
print("Please try again")
LogOn()
The else branch is called already for the first iteration (with x = 0)!
You should check after the while-loop if an account was found and otherwise print your error message.
Instead of recursing to LogOn() you could better use an outer (endless-)while-loop which calls LogOn(). In LogOn then just do a return in error case.
A few observations:
The else branch is called on the first iteration when x=0. You need to finish the for loop, then branch if the account has not been found.
if pin in accounts[x] is a security hole because it allows people to use their name or account number as their pin!
"if accnum in account[1]" should be "if accnum == account[1]"
Hope that helps!
accounts=[
["Luke",'00001','1234',1337],
["Louis",'00002','4321',420],
]
name = ""
x = []
def LogOn():
global name
global x
print ("Welcome to the Bank of Bailey")
accnum = raw_input("-please enter your account number-")
if len(accnum) != 5:
print("That number is not valid, please enter a valid number")
LogOn()
else:
found = False
for account in accounts:
if accnum == account[1]:
found = True
name = account[0]
print ("Account found")
pin = raw_input("-please enter your pin-")
if pin in account[2]:
print ("Pin found")
MainMenu()
else:
print("Pin not found")
print("Please try again")
LogOn()
break
if not found:
print("Account not found")
print("Please try again")
LogOn()
I like #TimSC's answer, but I'll add a few more observations:
LogOn is not a good function name; it should be log_on to match PEP8 naming conventions (LogOn suggests it is a class rather than a function).
You declare name and x as globals, then never use them. Globals are almost always a bad idea, and unused declarations just clutter your code.
As #CTX pointed out, you are using recursion (LogOn calling LogOn calling MainMenu calling LogOn etc) where iteration would make a lot more sense - you should back out on an error, not call again a level deeper.
Mixing input/output code and action code is usually a bad decision; it makes your code less flexible and reusable and often harder to debug as well. You should instead have an input/output function which calls an action function with the values it needs.
Giving separate error messages for bad account number, bad pin number is a security hole; it makes it much easier for would-be attackers to find valid account numbers to attack.
Looking things up in a list is relatively slow (O(n) ie time proportional to the number of items in the list). Use a dict instead (O(1) ie constant time - a quick hash calculation takes you right to the item you are looking for).
Here is a fancied-up version; may it give you things to think about:
import sys
# version compatibility shim
if sys.hexversion < 0x3000000:
inp = raw_input # Python 2.x
else:
inp = input # Python 3.x
class Account:
index = {}
__slots__ = ("accnum", "pin", "name", "balance")
#classmethod
def log_in(cls, accnum, pin):
key = (accnum, pin)
acc = Account.index.get(key, None)
if acc is None:
raise ValueError("No such login (bad account# or PIN)")
else:
return acc
def __init__(self, accnum, pin, name, balance):
# save values
self.accnum = accnum
self.pin = pin
self.name = name
self.balance = balance
# add self to account index
key = (accnum, pin)
Account.index[key] = self
# create accounts
Account('00001', '1234', "Luke", 1337)
Account('00002', '4321', "Louis", 420)
def main():
while True:
print("\nWelcome to the Bank of Bailey")
accnum = inp("Please enter your account number: ").strip()
pin = inp("Please enter your PIN: ").strip()
try:
acc = Account.log_in(accnum, pin)
print("\nYour account has a current balance of ${:0.2f}".format(acc.balance))
print("Thank you for banking with us!")
except ValueError as ve:
print(ve)
if __name__ == "__main__":
main()