python-3.xclassclass-instance-variables

Can't figure out how to create a "list" instance variable using class in Python


This is my code:

class Category():

    
    def __init__(self,category,balance=0,ledger=[]):
        self.category = category
        self.balance = balance
        self.ledger = ledger

    def check_funds(self,amt):
        if amt > self.balance:
            return False
        else:
            return True
    

    def deposit(self, dep_amt, description=""):
        self.balance +=dep_amt
        dep_note = "{\"amount\": "+str(dep_amt)+", \"description\": "+description+"}"
        self.ledger.append(dep_note)
        
    def withdraw(self, wd_amt, description=""):
        if not self.check_funds(wd_amt):
            return False
        else:
            self.balance -= wd_amt
            wd_note = "{\"amount\": "+"-"+str(wd_amt)+", \"description\": "+description+"}"
            self.ledger.append(wd_note)
            return True
        
    def get_balance(self):
        return self.balance
    
    def transfer(self,tf_amt,category):
        wd_description = "Transfer to "+category.category
        dp_description = "Transfer from "+self.category
        self.withdraw(tf_amt,wd_description)
        category.deposit(tf_amt,dp_description)
    
    

Creating instances:

food = Category('food')
food.deposit(1000,"food initial deposit")
food.withdraw(300,"groceries")

clothing = Category('clothing')
clothing.deposit(1000,"clothes initial deposit")
clothing.withdraw(20,"pants")
food.transfer(200,clothing)
    

While running the code clothing.ledger this is the output:

['{"amount": 1000, "description": food initial deposit}', '{"amount": -300, "description": groceries}', '{"amount": 1000, "description": clothes initial deposit}', '{"amount": -20, "description": pants}', '{"amount": -200, "description": Transfer to clothing}', '{"amount": 200, "description": Transfer from food}']

This is what I'm looking for:

['{"amount": 1000, "description": clothes initial deposit}', '{"amount": -20, "description": pants}', '{"amount": -200, "description": Transfer to clothing}']

basically my ledger attribute take all the instances which is what I don't want.


Solution

  • When passing dynamic or mutable(list, dictionary) default values in Python it is best practice to set them as None and to specify their intended value(s) inside the function.

    def __init__(self,category,balance=0,ledger=None):
        If ledger is None:
            ledger = []
        self.category = category
        self.balance = balance
        self.ledger = ledger
    

    Otherwise ledger is only evaluated a single time. Reference: https://medium.com/python-features/how-to-avoid-classic-pitfall-while-passing-default-values-in-python-7002c0dc4c7c