0

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.

khelwood
  • 55,782
  • 14
  • 81
  • 108
Zack
  • 45
  • 5
  • You're not properly using the static variable correctly. See here fore more details: https://stackoverflow.com/questions/26630821/static-variable-in-python – mattsap Mar 07 '19 at 23:35

3 Answers3

1

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
blhsing
  • 91,368
  • 6
  • 71
  • 106
0

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')})
Ben
  • 5,952
  • 4
  • 33
  • 44
  • In your first example, you can just do `self.user_list[uid] = self`, you don't need to do `Account.user_list[uid] = self`. As long as you never assign `self.user_list` itself (just to keys within it), `self.user_list` will seamlessly read from the class attribute. – ShadowRanger Mar 08 '19 at 00:02
  • @ShadowRanger, true, but I like to be explicit about my static variables. – Ben Mar 08 '19 at 03:00
0

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

Dejan S
  • 1,445
  • 1
  • 8
  • 14
  • This is what has worked best for me. Now just working on the best way to use deposit and withdraw methods on an object that was created through the class method. – Zack Mar 08 '19 at 03:21