Return Dictionary in using str in python - 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]

Related

AttributeError: class object has no attribute

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

Updating the method references on VS code

I am having a hard time figuring out how to update selected references of a method from vscode. Right-clicking on the method name doesn't give the options to choose and update the references. New to Python and vscode and trying to figure out the nuances around it. Can some help me with this please!
Here are the classes - I have a class Player_Account
class Player_Account:
def __init__(self,owner,balance):
self.owner = owner
self.balance = balance
def deposit(self,balance):
self.balance += balance
return "Amount added to players pot !"
def withdraw(self,amount): # I need to update this method name to withdraw_amount
if self.balance<amount:
return "Funds Unavailable"
else:
self.balance -= amount
return "Money added to hand !"
def __str__(self):
return f"Account owner : {self.owner} has outstanding balance of {self.balance}"
Another class Player
class Player:
def __init__(self,name):
self.name=name
self.hand = []
self.player_account:Player_Account = Player_Account(name,0)
def initial_money(self,amount):
self.player_account.balance = amount
def player_won_the_hand(self,amount):
self.player_account.deposit(amount)
return True
def player_betting_amount_for_the_round(self,amount):
value = self.player_account.withdraw(amount) # I need this reference to be automatically updated as well
if value == 'Funds Unavailable':
return False
else:
return True
I just tried.
set cursor on def withdraw
press F2 (rename symbol)
change name to withdraw_amount and press Enter
it takes a few seconds but both are changed
I use PyLance.

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()

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')})

Using variables to create class objects

This is my first question on here, so I hope I am asking the 'right' way. The code below is supposed to generate a class object, which should be named via the function createAccount() at the end. I was expecting the account to be a combination of surname and dob, however it creates the class object called accountName and not the product of the variable itself. I can see why it is doing this, but i cannot see how to correct it.
class Account(object):
def __init__(self, balance):
self.balance = balance
def deposit(self,amount):
self.balance += amount
print(self.balance)
return self.balance
def withdraw(self,amount):
if amount <= self.balance:
self.balance -= amount
print(self.balance)
return self.balance
else:
print("You do not have sufficient funds for this transaction, please contact your local branch manager")
def printBalance(self):
print(self.balance)
def createAccount():
name = input("Client Surname")
dob = input("client Date of Birth")
accountName = name+dob
print(accountName) # for debug
accountName = Account(0) # opening account balance is £0
return accountName
I think what you want is something like a "name" field in your Account object. For example:
class Account(object):
def __init__(self, name, balance):
self.name = name
self.balance = balance
. . .
def createAccount():
name = input("Client Surname")
dob = input("client Date of Birth")
accountName = name + dob
print(accountName) # for debug
account = Account(accountName, 0.0) # opening account balance is £0
return account
The object returned by createAccount contains both the account balance and the name on the account.
You are creating a variable accountName and assigning to it a text string object whose contents is the name and date of birth.
Next you're clobbering that and reassigning accountName with a new Account object you're creating. The old value for accountName gets lost when you assign something new to it.
What you need to do is pass name+dob to Account's init function, and in that function, assign the passed account name to an object variable such as self.accountName:
def __init__(self, name, balance):
self.accountName = name
self.balance = balance
...
def createAccount():
name = input("Client Surname")
dob = input("client Date of Birth")
account = Account(name+dob, 0) # opening account balance is £0
return account
Note that it's a bad idea to use name+dob as the account name, because later it'll be hard to figure out where the name ends and the date of birth begins. But at least, this will get you started.

Categories