I'm in doubt with this program of mine with inheritance, I don't know if I understand the concept wrong or the code is wrong (maybe both), but I really need some help.
The other functions are working, the only problem is when I try to access the Saving class function by the Account (Subclass).
class Savings:
def __init__(self):
self.money = 0
self.statement = []
def apply(self, value):
self.money += value
self.statement.append(("Apply", f"${value}"))
class Accounts(Savings):
def __init__(self, client: Client, bank: Bank):
super().__init__()
#other variables
def change_money(self):
print("3 - Apply in Savings")
choose = int(input("Choose: "))
elif choose == 3:
value = float(input("Value to apply: $").replace(",", "."))
super().apply(value)
print(super().money)
else:
pass
And when I try to access the money variable, it says
super().money
AttributeError: 'super' object has no attribute 'money'
I made a test using only Accounts as Object and the money variable changed,
Input:
a = Accounts()
a.change_money()
a.money
Output
3 - Apply in Savings
Choose: 3
Value to apply: $100
100.0
but Accounts and Savings are different classes and I need to access it and change from the Subclass
Please, can anyone help me ?
You can use self.apply(value) instead:
class Savings:
def __init__(self):
self.money = 0
self.statement = []
def apply(self, value):
self.money += value
self.statement.append(("Apply", f"${value}"))
class Accounts(Savings):
def change_money(self):
value = float(input("Value to apply: $"))
self.apply(value)
print(self.money)
a = Accounts()
a.change_money() # input, say, 10
print(a.statement) # [('Apply', '$10.0')]
Your object a inherits the method apply attached to itself, so a can call its own method by self.apply.
You don’t need to call super as it is a pre defined function and is part of the savings accounts class. Just call self.apply(value)
Related
I am trying to use the transfer_to_saving method in the CheckingAccount class. However, whenever I create a SavingAccount object, the self.has_saving = True does not change the class attribute to True. So, whenever I try to transfer funds, it prints Must create a saving account.
class CheckingAccount(Account):
balance = 0
def __init__(self, account_number, pin):
super().__init__(account_number)
self.SavingAccount = SavingAccount
self.pin = pin
def deposit(self, amount):
old_bal = self.balance
self.balance += amount
print(f'Previous Balance: ${old_bal}\nDeposit amount: ${amount}\nNew Balance: ${self.balance}')
def withdraw(self, pin, amount):
if pin == self.pin:
self.balance -= print('Insufficient funds') if amount > self.balance else amount
else:
print('Invalid PIN')
def transfer_to_saving(self, amount):
if self.SavingAccount.has_saving is False:
print('Must create a saving account')
elif amount > self.balance:
print('Insufficient funds')
else:
self.SavingAccount.balance += amount
self.balance -= amount
class SavingAccount(Account):
balance = 0
has_saving = False
def __init__(self, account_number):
super().__init__(account_number)
self.CheckingAccount = CheckingAccount
self.has_saving = True
def deposit(self, amount):
self.balance += amount
Am I doing this right? Shouldn't the init method be changing the class attribute?
---UPDATE---
The goal I am trying to accomplish is to find out whether the user has already created a saving account. I have additional User classes that I did not include since it would be a bit overkill. However, the goal is to prevent a user from transferring money from checking to saving if they don't have a saving account.
You are not actually creating an instance of SavingAccount with this line:
self.SavingAccount = SavingAccount
You are assigning the self.SavingAccount attribute to the SavingAccount class defined below.
You need to call the SavingAccount constructor, like this:
self.saving_account = SavingAccount(account_number)
Note that the Python convention is to use lower_snake_case for attributes/variables, and UpperCamelCase for class names.
You are doing the same thing on this line in the SavingAccount constructor:
self.CheckingAccount = CheckingAccount
I'm not sure what the goal is here, but if you want every SavingAccount to hold a reference to a CheckingAccount and vice versa, it might be cleaner to do it like this:
class CheckingAccount(Account):
def __init__(self, account_number, pin):
super().__init__(account_number)
self.saving_account = SavingAccount(account_number, self)
self.pin = pin
class SavingAccount(Account):
def __init__(self, account_number, checking_account):
super().__init__(account_number)
self.checking_account = checking_account
With this, whenever you create a CheckingAccount you will get a corresponding SavingAccount and they will each hold a reference to each other. I think it's still a bit weird conceptually, since the account numbers would be the same, so it might be better to just create them separately like this:
class CheckingAccount(Account):
def __init__(self, account_number, pin):
super().__init__(account_number)
self.saving_account = None # to be assigned later
self.pin = pin
class SavingAccount(Account):
def __init__(self, account_number):
super().__init__(account_number)
self.checking_account = None # to be assigned later
checking_account_number = 123
checking = CheckingAccount(checking_account_number)
saving_account_number = 456
saving = SavingAccount(saving_account_number)
checking.saving_account = saving
saving.checking_account = checking
Finally, the has_saving attribute of SavingAccount is not necessary at all. A cleaner way to check if a SavingAccount is to use isinstance:
def transfer_to_saving(self, amount):
if not isinstance(self.saving_account, SavingAccount):
print('Must create a saving account')
elif amount > self.balance:
print('Insufficient funds')
else:
self.saving_account.balance += amount
self.balance -= amount
When you do the self.has_saving = True you are establishing an instance variable that is part of the instance. you are not modifying the class variable. to modify the class variable you would need to use the class name instead of self. reference.
UPDATE
Tells me that TypeError: __init__() missing 1 required positional argument: 'storlek'
My class
class Hanterare:
def __init__(self, storlek):
self.storlek =storlek
My functions
def fråga_storlek():
try:
Hanterare().storlek =int(input('Choose size'))
except ValueError:
print("Wrong try again!!")
fråga_storlek()
And I want to use the value, the user has chosen and call them into my other functions for example:
def getNewBoard():
board = []
for i in range(fråga_storlek()):
board.append([' '] * fråga_storlek())
Unless I'm missing a notation, Q is a terrible name. Variable and method names should be in lowercase, and describe the purpose of the variable. board_width would be a much better name.
Having a method with the same name as a class member is confusing. Since you're asking for the board size, I'd rename the method to something like ask_board_size.
After taking the above into consideration, the problem solves itself:
class BoardHandler(self, board_size):
self.board_size = board_size
def ask_board_size(self):
try:
self.board_size = int(input("Choose size please"))
except ValueError:
print("Wrong try again!")
ask_board_size()
And is that constructor a new notation? It should probably use __init__:
class BoardHandler:
def __init__(self, board_size):
self.board_size = board_size
...
No, to create a field in a class, you should declare it in a function called __init__(self). Like so:
class BoardHandler:
def __init__(self, Q):
self.Q = Q
You can also take input upon creation instead of having it as a parameter, like so:
class BoardHandler:
def __init__(self):
self.Q = int(input("What size would you prefer?"))
You don't want to use:
class BoardHandler:
self.Q = 5 #some number
unless you want the board size to be the same across all BoardHandlers.
Then you can access it in other methods of the class by just using self.Q.
To use it outside the class, here's how:
b_size = int(input("What size?"))
bh = BoardHandler(b_size)
print("The board size is: " + str(bh.Q))
I am planning to design a program to track profit and loss of my stock account, then I used Python and hope to solve it in a Object Oriented way.
Code:
class PNL(object):
stock_amount = {}
def __init__(self,cash,position):
self.cash = cash
self.position = position
def buy(self,Stock,amount):
pass
def sell(self,Stock,amount):
pass
def stock_amt(self,Stock):
if Stock().symbol not in stock_amount:
stock_amount[Stock().symbol] = 0
else:
return stock_amount
class Stock():
def __init__(self,symbol,timestamp,price):
self.symbol = symbol
self.time = timestamp
self.price = price
a = PNL(0,0)
APPL = []
APPL.append(Stock('APPL',0,10))
APPL.append(Stock('APPL',1,12))
a.stock_amt('APPL')
for stock in APPL:
if stock.time == 0:
print stock.price
But this doesn't work fine, anyone has idea on that?
Firstly you need to fix the class PNL, when you declare the methods with Stock, as its an argument/parameter, you'd better choose another name, or write it in lowercase to make difference with the class Stock.
Just think you will give an instance to these methods, no need to write the type, and by the way, no need to instantiate again the class inside the method by doing Stock().symbol, you'll give an instance, or directly the attribute symbol if you prefer.
Also, the stock_amount can be stored as a instance attribute, as below :
class PNL(object):
def __init__(self,cash,position):
self.cash = cash
self.position = position
self.stock_amount = {}
def buy(self,stock,amount):
pass
def sell(self,stock,amount):
pass
def stock_amt(self,stock):
if stock.symbol not in self.stock_amount:
self.stock_amount[stock.symbol] = 0
else:
return self.stock_amount
Then when you call your classes, i think you wanted to loop on the list APPL you've built (then just call a.stock_amt(stock_object_created) :
a = PNL(0,0)
APPL = []
APPL.append(Stock('APPL1',0,10))
APPL.append(Stock('APPL2',1,12))
for stock in APPL:
a.stock_amt(stock)
if stock.time == 0:
print stock.price
print a.stock_amount
#>>>10
#>>>{'APPL2': 0, 'APPL1': 0}
I want to create a function within a class that can access two different members with the same function. For example in the code below, I want both of the lines below to use the 'apply' function on different variables in the class
print(state.apply(rate))
print(state.apply(wage))
I had thought if I put in a dummy variable in the function definition (called exposure), it would replace it with the variables passed to the function (rate and wage in the example below). What is the correct way of doing this in python 3?
class State():
def __init__(self):
self.rate = 0
self.wage = 0
def apply(self, exposure):
self.exposure = self.exposure - 1
return self.exposure
state = State()
rate = State.rate
wage = State.wage
print(state.apply(rate))
print(state.apply(wage))
EDIT: I had made a typo where I had State instead of state in each print statement. I have now corrected this
This would be the only way:
class State:
def __init__ (self):
self.rate = 0
self.wage = 0
def apply (self, exposure):
setattr(self, exposure, getattr(self, exposure) - 1)
return getattr(self, exposure)
>>> state = State()
>>> print(state.apply('rate'))
-1
>>> print(state.apply('wage'))
-1
>>> print(state.apply('wage'))
-2
Note that those are instance variables, so you cannot access them using the type, State, but only using the object, state.
However, I would say, that whatever you are trying, you’re doing it wrong. If you describe your actual problem, we may be able to suggest a way better solution for it instead.
I have been learning Python as my first language for about two weeks now and I love it. I have been using Learn Python the Hard way, but when I hit Object Oriented Programming my brain just about exploded. I did many hours of research and I thought I finally got the gist, but now I am a little stuck.
I have created a very simple banking program, attempting to use Classes. I was doing fine, until I hit a big issue. As it is, it works (I have not posted the menu setup for brevity, but it does what I want as long as I only have these three objects.) There in lies the problem.
Issue: How do I manipulate instance values if there are multiple instances. TLDR: How can I not hard code object references?
Please see the Transfer function in my main BankAccount Class: I hardcoded in the objects(accounts) saccount.balance and paccount.balance variables, but what if there were many different accounts? How would I be able to edit their balances aka do transfers?
How can I make the Transfer() method correctly reference the instances they need to go to? Am I asking this right? Am I using OOP incorrectly?
What if there were multiple users or multiple bank accounts? like "daccount", "faccount" etc how would I manage their balances and transfers?
Please be gentle...
Here is my main Class:
class BankAccount:
#### NO CLASS VARIABLES
def __init__(self):
self.balance = 500 #This is an instance variable
def withdraw(self, amount):
self.balance = self.balance - amount
print "You withdrew %d dollars\n" % amount
return self.balance
def deposit(self, amount):
self.balance += amount
print "You deposited %d dollars\n" % amount
return self.balance
def transfer(self, amount): ### Here is our problem
print "Where would you like to transfer money from?"
answer = raw_input("1.) From CHECKINGS to SAVINGS\n2.)From SAVINGS to CHECKINGS\n >>>")
if answer == "1":
baccount.balance -= amount #What would I do if there were many accounts?
saccount.balance += amount #I originally tried this as SavingsAccount.balance, but that would be a "Class Variable" correct?
elif answer == "2":
saccount.balance -= amount
baccount.balance += amount
else:
menu()**
def printbal(self):
print "Your balance is currently %d dollars." % self.balance
return self.balance
Here are my two subclasses (A minimum balance checkings, and a savings)
class MinBalAccount(BankAccount): #This is a BankAccount and has a MinBal
def __init__(self, minbalance): #This sets our minbalance during 'instantation'
BankAccount.__init__(self) #This gives us the variable self.balance
print "ATM INITIALIZED. WELCOME TO SKYNET BANK"
self.minbalance = minbalance #Sets the minimum balance for this minbalaccount
def withdraw(self, amount):
while self.balance - amount < self.minbalance: #THis allows for a loop,
print "Apologies, you must maintain a balance of 1.00"
print "If you withdraw %d from your current balance of %d it will leave you with a balance of %d dollars." % (amount, self.balance, self.balance - amount)
print "Please Re-Enter The AMOUNT You would like to withdraw"
amount = int(raw_input("\nAmount:"))
BankAccount.withdraw(self, amount)
self.printbal() #We can do this because we inherited it from out parent class. We could also write it as MinBalAccount.printbal(self) or BankAccount.printbal(self)
class SavingsAccount(BankAccount):
def __init__(self,minbalance,balance):
self.minbalance = minbalance
self.balance = balance
paccount = BankAccount()
baccount = MinBalAccount(1.00)
saccount = SavingsAccount(300, 500)
How can I make the Transfer() method correctly reference the instances they need to go to? Am I asking this right?
Am I using OOP incorrectly?
You declare object references in Python the same way you do any other variable, you run the constructor of the class and assign it to a value. If you want to transfer from one account and into another account (regardless of the account), you want to pass the object references as arguments to the function in the method (assuming these accounts are separate from each other).
Consider the design of your BankAccount class: You're currently using your transfer method to transfer from two fixed accounts. If you want to transfer from the current BankAccount object (IE "self"), to another account (whichever one is passed to the method), you would write your method like so:
def transferTo(self, otherAccount, amount):
if (self.balance >= amount):
self.balance -= amount
otherAccount.balance += amount
Then when you call this method, you simply indicate which account to transfer the funds to.
baccount.transferTo(saccount, 100)
And you're done! I would recommend keeping the IO operations (such as asking the user for input) outside of these methods since you could want to perform transfers that don't need user input.
You can treat object references the same way you could any other value. Therefore you can pass them to any method, place them in a list, etc.
What if there were multiple users or multiple bank accounts? like "daccount", "faccount" etc how would I manage their balances and transfers?
You should separate the concept of an AccountHolder from each BankAccount. An AccountHolder may have multiple BankAccounts, and each BankAccount is then provided it's own balances, number, etc. You can assign class instances to instance variables in the method of a class. The AccountHolder class should have a list of BankAccount objects, and provide some basic methods that return certain key accounts (such as a checkingAccount() method). A constructor like this would work well for a User:
class AccountHolder:
def __init__(self, name):
self.user_name = name
self.checking = BankAccount()
self.savings = MinBalAccount()
I believe, however, that the key to your question is to pass the object references as arguments to methods, allowing you to more generically treat each instance of a BankAccount. Understandably this is your first real encounter with OOP, so it's certain to be overwhelming. I wish you luck!
You have to modify your transfer function. It needs 1) the amount 2) the destination account
def transfer(self, amount, destination): ### Here is our problem
self.balance -= amount
destination.balance += amount
And add the following code at the end
print "Where would you like to transfer money from?"
answer = raw_input("1.) From CHECKINGS to SAVINGS\n2.)From SAVINGS to CHECKINGS\n >>>")
amount = int(raw_input("Amount to transfer ? "))
if answer == "1":
baccount.transfer(amount, saccount)
elif answer == "2":
saccount.transfer(amount, baccount)
else:
menu()**
IMO you're running into an issue here because transfer() isn't really a good interface for a BankAccount instance. withdraw() and deposit() make sense on their own, but transfer() would at least require passing another argument, rather than hard-coding a global variable (in general i try to avoid using global variables).
What I would do instead is to have another class e.g. User which owns the paccount, baccount, saccount variables, in addition to the transfer(), deposit(), and withdraw() methods which guide you through the menu e.g.:
class User:
def __init__(self):
self._paccount = BankAccount()
self._baccount = MinBalAccount(1)
self._saccount = SavingsAccount(300, 500)
def deposit(self, amount):
num = input('Where do you want to deposit your money? 1) Savings 2) MinBal 3) Checking').strip()
if num == '1':
self._saccount.deposit(amount)
...
def transfer(self, amount):
print('Where would you like to transfer money from?')
...
user = User()
user.deposit(200)
user.transfer(500)