Why is my class object not working as intended?

Tags: , , ,



I have two issues that need resolving. I have created a class object LoanInstance. The object should create a list of numbers (int or float) that show different aspects of a personal loan repayment balance. There are 2 main parts to the object.

Part 1: Read in data from a data frame (I’ve created an example data frame below)

df = {'amount':[7000], 'term':[36], 'apr':[0.145], 'product':['standard'], 'score':[750], 'customer_type':[Home], 'Channel':[trad]}

Part 2: Generate the repayment profiles for the loan

Part 1 is working fine. However, part 2 is not working as I expect.

These are the steps:

Step 1: create a loan object

loans = LoanInstance()

Step 2: read in data from pandas dataframe (this works fine)

loans.get_loan(df,1)

Step 3:generating the balance profiles

balance profiles are generated with the following method applied to the loan object.

loans.repayment_profiles()

Issue 1!

This produces the error: TypeError: ‘int’ object is not callable.

It is being caused by the expression below:

monthly_repayment = self.amount/(12(1 - (1 + (self.apr/12))**-n*12))

What’s going wrong here?

Issue 2

When I bypass issue 1 by replacing the problematic expression with a number (i.e 200) I can get the code to run.

loans.repayment_profiles()

However, when I try to print any of the balance profile attributes they come up as an empty list [ ].

i.e running the code below comes out as an empty list [ ]

loans.balance_profile_start

Why is this happening ? I expected a list of numbers represented the repayment balance for the loan taken into the object in step 1.

Thanks for your help in advance!

Full class code is here:

class LoanInstance:
def __init__(self, 
             amount=0, 
             term=0, 
             apr=0, 
             product=0, 
             score=0, 
             customer_type=0, 
             channel=0,
             balance_profile_end =[], 
             balance_profile_start=[],  
             interest_profile=[], 
             recieved_interest=[], 
             recieved_capital=[]
             ):
    
    self.amount = amount 
    self.term = term 
    self.apr = apr
    self.product = product 
    self.score = score 
    self.customer_type = customer_type 
    self.channel =  channel
    
    self.balance_profile_start = balance_profile_start  # Starting balance profile over loan term
    self.balance_profile_end = balance_profile_end  # End balance profile over loan term
    self.interest_profile = interest_profile  # Interest accrued over loan term
    self.recieved_interest = recieved_interest  # Recieved interest profile
    self.recieved_capital = recieved_capital   # Recieved capital profile
    

# Read in loan attributes from pandas dataframe 
def get_loan(self, df, row):
    self.amount = df.at[row, 'amount']
    self.term = df.at[row, 'term']
    self.apr = df.at[row, 'apr']
    self.product = df.at[row, 'product']
    self.score = df.at[row, 'score']
    self.customer_type = df.at[row, 'customer_type']
    self.channel = df.at[row, 'Channel']


# Generate contractual balance profiles 
def repayment_profiles(self):
    
    n = self.term/12  # Repayment term in years 
    nominal_interest = (((self.apr + 1)**(1/12))-1)*12  # Nominal interest rate: APR excluding other fees
    monthly_rate = nominal_interest/12  # Monthly customer rate
    monthly_repayment = self.amount/(12(1 - (1 + (self.apr/12))**-n*12))  # Fixed monthly repayment 
    
    return print(nominal_interest)
    
    
    # Generate contractual repayment over the term of the loan
    
    for month in range(0, self.term + 1):  # Set special case for month 0
        
        if month == 0:
            
            interest = recieved_int = 0
            recieved_capital = 0
            balance_start = 0  # Gives a starting balance profile of 0 at month 0
            balance_end = self.amount
            
            self.interest_profile.append(interest)  # Append interest to interest profile
            self.balance_profile_end.append(balance_end)  # Append balance to balance profile end
            self.balance_profile_start.append(balance_start)  # Append balance to balance profile start
            self.recieved_interest.append(recieved_int)  # Append recieved interest
            self.recieved_capital.append(recieved_capital)  # Append recieved capital
        
        elif month == 1:  # set special case for month 1
    
            balance_start = self.amount
            self.balance_profile_start.append(balance_start)
            
            interest = recieved_int = monthly_rate*self.balance_profile_start[1]
            self.interest_profile.append(interest)
            self.recieved_interest.append(recieved_int) 
            
            balance_end = self.balance_profile_start[1] + self.interest_profile[1] - monthly_repayment 
            self.balance_profile_end.append(balance_end)
            
            recieved_capital = monthly_payment - self.interest_profile[1]
            self.recieved_capital.append(recieved_capital)
        
        else:
            
            balance_start = self.balance_profile_end[month]
            self.balance_profile_start.append(balance_start)
            
            interest = recieved_int = monthly_rate*self.balance_profile_start[month]
            self.interest_profile.append(interest)
            self.recieved_interest.append(recieved_int) 
            
            balance_end = self.balance_profile_start[month] + self.interest_profile[month] - monthly_repayment 
            self.balance_profile_end.append(balance_end)
            
            recieved_capital = monthly_payment - self.interest_profile[month]
            self.recieved_capital.append(recieved_capital)
        
        return self.balance_profile_start, self.balance_profile_end, self.interest_profile, self.recieved_interest, self.recieved_capital
    

Answer

For the first issue,

Multiplication operator (*) is used to perform multiplication. In your case, self.amount/12(...) note the missing * operator between 12 and (. Because of the missing operator, it treats 12 as a callable (function). But 12 is an int and not a callable, hence the error. So insert the * if you mean multiplication. Also, I would suggest properly insert the brackets to avoid ambiguity. For example, in the case of **-n*12, you can change it to **(-n*12). If this is what it means.

For the second issue,

Note the return statement, return print(nominal_interest). A return statement is used to end the function right there and return the value where the function was called. Meaning, the function stops executing at this line, and all the further instruction are skipped. And since, by default balance_profile_start is [], it displays an empty list. You probably only want to print nominal_interest, instead of returning it. So the line becomes just: print(nominal_interest)



Source: stackoverflow