AttributeError: class object has no attribute - python

I am new to python. I try to access the attribute acnt_amount from the class bank_Customer, but throws "AttributeError" error. How to access the attribute of the function getDetails to withdraw with in the class from one function to another function? What is the mistake that i do? Any help will be much appreciated! Thanks in advance!
Code:
class bank_Customer:
def getDetails(self, cname, acnt_no, acnt_type, acnt_amount):
self.cname = cname
self.acnt_no = acnt_no
self.acnt_type = acnt_type
self.acnt_amount = acnt_amount
row = self.cname + "," + str(self.acnt_no) + "," + self.acnt_type + "," + str(self.acnt_amount) + "\n"
file = open('cust_details.csv','a')
file.write(str(row))
file.close()
print('*'*40)
print("Account has been added successfully!")
return self.acnt_amount
def withdraw(self):
cash = int(input("Please enter the amount to be withdrawn: "))
self.acnt_amount = self.acnt_amount - cash
f"balance amount is {balance}"
return balance
base = bank_Customer()
base.withdraw()
Error:
Traceback (most recent call last):
File "C:\Users\kisha\IdeaProjects\Git projects in python\ATM application.py", line 96, in <module>
base.withdraw()
File "C:\Users\kisha\IdeaProjects\Git projects in python\ATM application.py", line 66, in withdraw
self.acnt_amount = self.acnt_amount - cash
AttributeError: 'bank_Customer' object has no attribute 'acnt_amount'

As suggested, an init is required. Also consider setting up some defaults, and look at the use of "getters and setters".
You may gain some insight from the following sample bank account class that I wrote some time ago as an example.
# #Author:srattigan
# #Date:2020-12-10 11:10:33
# #LastModifiedBy:srattigan
# #Last Modified time:2020-12-14 09:50:13
# demo class for inheritance
class BankAccount:
"""Generic Bank Account
"""
acc_num = 100000
def __init__(self, name, balance=0):
self.name = name
self.balance = balance
self.account_num = self.acc_num
BankAccount.acc_num += 1
def deposit(self, amount):
assert amount > 0, ValueError("Must deposit a positive amount")
self.balance += amount
def withdraw(self, amount):
self.balance -= amount
def __str__(self):
rep = f"Bankaccount for {self.name}"
rep += f"\n\tAcc Num: {self.account_num}"
rep += f"\n\tBalance: €{self.balance:.2f}"
return rep
customer = BankAccount("Fred Jones", 99)
print(customer)

You need to def init as your first method. Thats where you specify cname, acnt_no etc.

you need to declare the variables inside the class first.
create the init() constructor to declare and initialize those variables

Related

Python code doesn't show date-time and also doesn't throw any errors

I've been learning python from an online course and in the oop section I made a simple bank account class with simple methods like deposit and withdrawal and the instructor also showed the use of datetime function from pytz and datetime. My static method in class doesn't throw an error except it gives me this <function "Class-Name"._time at 0x00000251A4D72790> instead of something like this
2021-07-30 21:40:47.669274+00:00 and the .astimezone throws this attribute error AttributeError: 'function' object has no attribute 'astimezone'
Meanwhile I also downloaded the instructors code and couldn't find any major difference in our code and the instructors code ran without any issues.
[import datetime
import pytz
class Account:
#staticmethod
def _time():
date = datetime.datetime.utcnow()
return pytz.utc.localize(date)
def __init__(self, name, balance):
self.name = name
self.balance = balance
self.trans_list = \[\]
def print_balance(self):
print("Current balance is {}".format(self.balance))
def deposit(self, amount):
if amount > 0:
self.balance += amount
self.print_balance()
self.trans_list.append((Account._time, amount))
def withdraw(self, amount):
if 0 < amount <= self.balance:
self.balance -= amount
self.print_balance()
self.trans_list.append((Account._time, -amount))
def transc_period(self):
for date_times, amount in self.trans_list:
if amount > 0:
tran_type = "deposited"
else:
tran_type = "withdrawn"
amount *= -1
print("{:6} {} on {} )".format(amount, tran_type, date_times))
if __name__ == '__main__':
account = Account("default", 0)
account.deposit(1000)
account.transc_period()
account.withdraw(500)
account.transc_period()][1]
The astimezone line comes in transc_period last line
[print("{:6} {} on {} )".format(amount, tran_type, date,date.astimezone()))][1]
I have corrected your code below. The key points were:
For the issue: <function "Class-Name"._time at 0x00000251A4D72790> you were referring to the function definition, but not actually invoking the function. So, you should call date_times() instead of date_times.
For the issue AttributeError: 'function' object has no attribute 'astimezone', the issue is related. Because you did not call the function, you could not call the underlying methods to the object the function generates.
Apart from that I removed a few parts of the code that seemed to be misplaced. (self.trans_list = [] --> self.trans_list = []) and (account.transc_period()][1] --> account.transc_period())
import datetime
import pytz
class Account:
#staticmethod
def _time():
date = datetime.datetime.utcnow()
return pytz.utc.localize(date)
def __init__(self, name, balance):
self.name = name
self.balance = balance
self.trans_list = []
def print_balance(self):
print("Current balance is {}".format(self.balance))
def deposit(self, amount):
if amount > 0:
self.balance += amount
self.print_balance()
self.trans_list.append((Account._time, amount))
def withdraw(self, amount):
if 0 < amount <= self.balance:
self.balance -= amount
self.print_balance()
self.trans_list.append((Account._time, -amount))
def transc_period(self):
for date_times, amount in self.trans_list:
if amount > 0:
tran_type = "deposited"
else:
tran_type = "withdrawn"
amount *= -1
print("{:6} {} on {}".format(amount, tran_type, date_times().astimezone()))
if __name__ == '__main__':
account = Account("default", 0)
account.deposit(1000)
account.transc_period()
account.withdraw(500)
account.transc_period()

4 Classes, 1 performs actions and asks for input, the others keep track of values

I'm working on a project for CS1410, where I need to simulate a Coffee Machine. I have quite a bit so far, but I'm a bit stuck, specifically with these questions:
In the class CashBox, under the function deposit, I'm trying to add the values together from any coins inserted in the oneAction function from the CoffeeMachine class. However I get the error "'CoffeeMachine' object has no attribute 'credit'" and I'm struggling with understanding why. I can tell it's an inheritance problem, but I'm unsure exactly how to fix it.
How should I format it so that when I get the input in oneAction(), I can take that input and mess with it in the cashBox? What am I doing wrong with self.something, and how can I recognize when to use self, and when to just use a normal variable
I wasn't sure how to upload the code so that the problem is reproducible without giving at least this file, it's all pretty tied together. Some advice on how I could have presented this better would be helpful as well.
Past the original question, any further advice would be seriously appreciated.
Seriously.
Thank you all, hopefully the code is pretty readable.
class CashBox(object):
def __init__(self):
self.credit = 0
self.totalReceived = 0.0
def deposit(self,amount):
self.credit = amount + self.credit
self.totalReceived = amount + self.totalReceived
print(self.totalReceived,self.credit)
def returnCoins(self):
print("Returning ", self.totalReceived, " cents.")
self.totalReceived = 0.0
def haveYou(self,amount):
return self.credit >= amount
def deduct(self,amount):
pass
def totalCoins(self):
return self.totalReceived
class CoffeeMachine(object):
def __init__(self):
self.cashBox = CashBox()
self.selector = self.cashBox
def oneAction(self):
while True:
command = input("""
______________________________________________________
PRODUCT LIST: all 35 cents, except bouillon (25 cents)
1=black, 2=white, 3=sweet, 4=sweet & white, 5=bouillon
Sample Commands: insert 25, select 1. Your command:
""")
words = command.lower().split()
if 'select' in words:
Selector.select(self,int(words[1]))
print("Great selection!")
elif 'insert' in words:
coinsAllowed = [5,10,25,50]
if int(words[1]) in coinsAllowed:
CashBox.deposit(self,int(words[1]))
else:
print("""
That is not one of the allowed coins,
please insert a penny, nickel, dime, quarter,
or half-dollar. Thank you.
""")
elif 'cancel' in words:
print("Cancelling transaction. Returning to main menu: ")
CashBox.returnCoins(self)
elif 'quit' in words:
print("Have a nice day!")
else:
print("That is not an option")
def totalCash(self):
pass
class Product(object):
def __init__(self,name,price,recipe):
self.name = name
self.price = price
self.recipe = recipe
def getPrice(self):
return self.price
def make(self):
print(self.recipe)
class Selector(object):
def __init__(self):
self.cashBox = CashBox
self.products = []
#self.products.append(Product.
def select(self, choiceIndex):
pass
def main():
m = CoffeeMachine()
while m.oneAction():
pass
#total = m.totalCash()
#print(f"Total Cash: ${total/100:.2f}")
if __name__ == "__main__":
main()
Exception has occurred: AttributeError
'CoffeeMachine' object has no attribute 'credit'
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 7, in deposit
self.credit = amount + self.credit
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 46, in oneAction
CashBox.deposit(self,int(words[1]))
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 89, in main
while m.oneAction():
File "C:\Users\Tanner Harmer\Desktop\Coffee2\CashBox.py", line 95, in <module>
main()
You're calling the CashBox by using the class name, like if the method were static, but you created an instance of this class (in the constructor self.cashBox = CashBox()) so use it
CashBox.deposit(self,int(words[1])) // OLD, NO
self.cashBox.deposit(self,int(words[1])) // YES
use the cashBox of the CoffeeMachine

How to store attributes of class instance in empty dictionary in Python?

I am making a custom class that performs basic banking functions.
class Account():
'''
A class to perform some basic banking functions
'''
UserList = {} #Empty dictionary to store (UID: name) for each new instance
def __init__(self, name, balance=0.0, uid=None):
self.name = name #The name of the account holder
self.balance = balance #The initial balance
self.uid = uid #User ID number chosen by account holder
#classmethod
def new_account(cls):
'''
New user can specify details of account through this class method via input()
'''
return cls(
input('Name: '),
int(input('Balance: ')),
int(input('UID: ')),
)
def withdraw(self, amount):
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
else:
self.balance -= amount
return print("After a withdrawl of {}, {}'s current balance is {}".format(amount, self.name, self.balance)) #printing balance after withdrawl
def deposit(self, amount):
self.balance += amount
return print("After a deposit of {}, {}'s curent balance is {}".format(amount, self.name, self.balance)) # printing balance after deposit
Basically, a new user is created by creating an instance of the Account() class and it accepts a name, initial balance, and a user ID. I added a class method to take this data in through user input when Account.new_account() is called. What I am now looking to do is store the User ID and name for each instance(account) in an empty dictionary. I have been playing around with this for a few hours, and what I was thinking was something like this
def add_user(self, uid, name):
UserList[int(self.uid)] = self.name
inserted somewhere but I tried implementing this in a few places in my code and it continued to just return an empty dictionary. Could someone help point me in the right direction. Also, the two other things I am trying to implement along with this is a way to prevent users from selecting the same UID and a way to require the UID to be exactly 5 numbers. I am relatively new to Python. Thank you.
You can define a dict as a class variable as you already did, but add the UID as a key to the dict in the __init__ method instead of a separate add_user method so that you can always validate the UID when an object is instantiated, no matter how:
class Account():
users = {}
def __init__(self, name, balance=0.0, uid=None):
if uid in self.users:
raise ValueError("UID '%s' already belongs to %s." % (uid, self.users[uid].name))
if len(uid) != 5 or not uid.isdigit():
raise ValueError("UID must be a 5-digit number.")
self.name = name
self.balance = balance
self.uid = uid
self.users[uid] = self
First noticed that you cant to a "return print(...", remove print.
You can do something like this
class Account():
'''
A class to perform some basic banking functions
'''
UserList = {} #Empty dictionary to store (UID: name) for each new instance
def __init__(self, name, balance=0.0, uid=None):
self.name = name #The name of the account holder
self.balance = balance #The initial balance
self.uid = uid #User ID number chosen by account holder
self.add_user(uid, name)
#classmethod
def new_account(cls):
'''
New user can specify details of account through this class method via input()
'''
return cls(
input('Name: '),
int(input('Balance: ')),
int(input('UID: ')),
)
def withdraw(self, amount):
if amount > self.balance:
raise RuntimeError('Amount greater than available balance.')
else:
self.balance -= amount
return "After a withdrawl of {}, {}'s current balance is {}".format(amount, self.name, self.balance) #printing balance after withdrawl
def deposit(self, amount):
self.balance += amount
return "After a deposit of {}, {}'s curent balance is {}".format(amount, self.name, self.balance) # printing balance after deposit
def add_user(self, uid, name):
self.UserList[int(uid)] = name
a = Account("new user", 100, 1)
a.add_user(2, "new user")
a.add_user(3, "new user")
print(a.UserList)
this will output {1: 'new user', 2: 'new user', 3: 'new user'}
Reference the static variable from the class name:
class Account():
user_list = {}
def __init__(self, uid):
self.uid = uid
Account.user_list[uid] = self
a = Account('uid')
print(a.user_list)
# {'uid': <__main__.Account object at 0x1043e7b38>}
For what it's worth, I think a better approach would be to use 2 classes (for convenience, I'm also using dataclasses to auto-generate some functionality - it doesn't affect the core logic). Then you don't have to worry about static variables at all.
import dataclasses
from typing import Dict
#dataclasses.dataclass
class Account:
uid: str
#dataclasses.dataclass
class Bank:
accounts : Dict[str, Account] = dataclasses.field(default_factory=dict)
def add_account(self, account):
if account.uid in self.accounts:
raise ValueError(f'UID : {account.uid} already exists!')
self.accounts[account.uid] = account
b = Bank()
a1 = Account('a1')
b.add_account(a1)
print(b)
# Bank(accounts={'a1': Account(uid='a1')})

Return Dictionary in using str in python

I have a bank account OOP project I am working on. And I can't seem to figure out this one bug. In brief, I would like to return a users bank account after they have added it. I have included all the code because I've solved this in an object-oriented way. The str() method seems to be the problem.
from enum import Enum
class AccountType(Enum):
SAVINGS = 1
CHECKING = 2
class BankAccount():
def __init__(self, owner, accountType):
self.owner = owner
self.accountType = AccountType(accountType)
self.balance = 0
def withdraw(self, amount):
if amount > self.balance:
raise Exception('Your balance is' + self.balance + 'cannot take this much money!')
else:
self.balance -= amount
def deposit(self,amount):
self.balance += amount
def __str__(self):
return "Owner: {}. Account type is: {} ".format(self.owner, AccountType(self.accountType).name)
def __len__(self):
return self.balance
#This class is responsible for returning information about the user and their account type.
class BankUser():
#initialize an accounts dictionary.
accounts = {}
def __init__(self, owner):
self.owner = owner
def addAccount(self, accountType):
if self.accounts.get(accountType) != None:
raise Exception('Cannot have more than 1 ' + AccountType(accountType).name + ' account!')
self.accounts[accountType] = BankAccount(self.owner, accountType)
#test if user inputs an account, otherwise throw an error
def getBalance(self, accountType):
return len(self.accounts[accountType])
def deposit(self, accountType, amount):
if (accountType in self.accounts and isinstance(self.accounts[accountType], BankAccount)):
self.accounts[accountType].deposit(amount)
else:
raise Exception(self.owner + ' does not have a ' + AccountType(accountType).name + ' account!')
def withdraw(self, accountType, amount):
self.accounts[accountType].withdraw(amount)
def __str__(self):
return "Your account is {}".format(AccountType(accountType).name)
user = BankUser("David")
user.addAccount(1)
print(user)
#OUTPUT
TypeError: __str__() missing 1 required positional argument: 'accountType'
I would like to return a users account. How do I do that? Everything I have tried has ended up with this error.
You will need to move the accounts dictionary to be owned by a single bank user instance, not the bank user class (move to the __init__)
Then, all your methods have accountType except __str__, so you cannot just access it as a variable, but you could return the whole dictionary instead.
class BankUser():
def __init__(self, owner):
self.owner = owner
#initialize an accounts dictionary.
self.accounts = {}
...
def __str__(self):
return "Accounts: {}".format(self.accounts)
Or you can do [AccountType(type).name for type in self.accounts]

Python Class Inheritance: Recursion Error

I'm trying to wrap my head around classes and I don't see what I have done wrong in this script. I have built a few nested classes.
import random
class Account(object):
num_accounts = 0
def __init__(self, name, balance):
self.name = name
self.balance = balance
Account.num_accounts += 1
def withdraw(self, amt):
self.balance = self.balance - amt
def inquiry(self):
return self.balance
class EvilAccount(Account):
def __init__(self,name,balance,evilfactor):
Account.__init__(self,name,balance)
self.evilfactor = evilfactor
def inquiry(self):
if random.randint(0,4) == 1:
return self.balance * self.evilfactor
else:
return self.balance
class MoreEvilAccount(EvilAccount):
def deposit(self,amount):
self.withdraw(5.00)
EvilAccount.deposit(self,amount)
class WithdrawCharge(object):
fee = 2.50
def withdraw_fee(self):
self.withdraw(self.fee)
class MostEvilAccount(EvilAccount,
WithdrawCharge):
def withdraw(self,amt):
self.withdraw_fee()
super(MostEvilAccount,self).withdraw(amt)
And then I instantiate it all with
d = MostEvilAccount("Dave", 500.00, 1)
And everything is fine. But when I try to call an inherited method:
d.withdraw(5.00)
I get recursion errors!
File "StackO.py", line 37, in withdraw
self.withdraw_fee()
File "StackO.py", line 33, in withdraw_fee
self.withdraw(self.fee)
File "StackO.py", line 37, in withdraw
self.withdraw_fee()
RecursionError: maximum recursion depth exceeded
This is right out of Python Essential Reference by David M. Beazley, p121.
Why am I getting Recursion Errors?
Your issue is that WithdrawCharge doesn't actually have a method called withdraw on it. So, when you call it from withdraw on MostEvilAccount, Python has to search for an appropriate method, which is withdraw on MostEvilAccount as the self you passed into WithdrawCharge.withdraw_fee is a MostEvilAccount. To illustrate:
d = MostEvilAccount("Dave", 500.00, 1)
d.withdraw(5.00)
--> In MostEvilAccount.withdraw at line 37
----> In WithdrawCharge.withdraw_fee at line 33
------> In MostEvilAccount.withdraw at line 37
--------> In WithdrawCharge.withdraw_fee at line 33
and it continues...
There are a few ways you could go about fixing this. You could take the functionality of WithdrawCharge and embed it in MostEvilAccount.withdraw. You could also pass Account.withdraw in to withdraw_fee as an argument and have it call that.
This error is here to prevent stack overflows. More info about how it works here

Categories