5
\$\begingroup\$

I'm looking for ideas on how to optimize the following code. I don't really know how to condense anything, I'm still very new to coding and this is the first time I've really created anything besides "Hello World".

import pandas as pd
import csv

#Method that calculates the Current Budget of the contents in the .csv file
def currentBudget():
    fileTransaction = open("transactions.csv", "r")
    info = fileTransaction.readlines()
    fileTransaction.close()
    budget = 0
    for line in info[1:]:
        budget += float(line.split(",")[2])
    print("\nCurrent Budget €"+str(budget)+"\n")

#Introductory using ASCII Markdown for Headers
def introduction():
    print("Budgetísimo".center(120,"-"))
    print("Welcome to Budgetísimo, a personal budget application that allows you to record and keep track of all your transaction\n")

#Choices of the User 
def userChoice():
    print("What would you like to do: ")
    print("(a) Record a Transaction")
    print("(b) Calculate Current Budget")
    print("(c) Exit Programme")

def userTransactionOutputOption():
    print("Please select one of the following options: ")
    print("(a) View Transactions using Date Range")
    print("(b) View specific Number of Transactions")

def transactionDate():
    data = pd.read_csv('transactions.csv', sep=",", index_col=0)

    data['Date'] = pd.to_datetime(data.Date)
    
    userStartDate = input("Start Date (DD-MM-YYYY): ")
    userEndDate = input("End Date (DD-MM-YYYY): ")

    afterStartDate = data["Date"] >= userStartDate
    beforeEndDate = data["Date"] <= userEndDate
    beweenDates = afterStartDate & beforeEndDate
    filteredDates = data.loc[beweenDates].sort_values(by="Date")
    print(filteredDates)

#The code
def userInputs():

    prompt = True

    while prompt == True:
        
        userInput = input("\nEnter your Choice: ").lower()
        df = pd.read_csv('transactions.csv', sep=",", index_col=0)
        dfData = pd.DataFrame(df)    

        if userInput == "a":
            fileTransaction = open("transactions.csv", "a", newline="")
            print("Please enter the following data when prompted to do so: ")
            userDescription = input("Description: ")
            fileTransaction.write(userDescription+",")
            userDate = input("Date (DD-MM-YYYY): ")
            fileTransaction.write(userDate+",")
            userAmount = input("Amount: ")
            fileTransaction.write(userAmount+"\n")
            currentBudget()
            print("Your Transaction has been recorded! :) \n")  
            fileTransaction.close()

        elif userInput == "b":
            currentBudget()

            transactionHistory = input("Would you like to see your Transaction History? (Y/N): ").lower()
            if transactionHistory == "y":
                userTransactionOutputOption()
                userTransactionOutput = input("Enter your Choice: ").lower()
                if userTransactionOutput == "a":
                    transactionDate()
                elif userTransactionOutput == "b":    
                    howManyTransaction = int(input("Please specify how many Transactions you want the System to Return: "))
                    print("\nYour Last "+str(howManyTransaction)+" Transactions: ")
                    print(df.tail(howManyTransaction))   
                else:
                    print("Please enter A (Date Range), B (Specific Transaction).")
                
            elif transactionHistory == "n":
                print("Your Last 10 Transactions: ")
                print(df.tail(-10).sort_values(by="Date"))
            else:
                print("Please enter Y (yes) or N (No).")

        elif userInput == "c":
            prompt = False
            print("\nProgramme Terminated\n")
            exit()

        else:
            print("Please enter A (Transaction Input), B (Transaction Output), C (Exit Programme).")

I am unsure how to reduce it, I have a file called app.py where I put the methods, but there is one method that contains what is essentially the entire code. I know this is not really good practice, but this is the first time doing anything like this and I'm really lost on what I should be doing. If anyone could help that would be amazing! :)

\$\endgroup\$
1
  • \$\begingroup\$ I really liked that you grouped related prints in functions to call repeatedly! One thing you might consider is factoring the different actions you take, depending on the userInput variable, into separate functions. That way, the body of your main function is cleaner and easier to read, and then you have a separate function for each functionality. \$\endgroup\$ – RGS Apr 13 at 10:44
4
\$\begingroup\$

Good first effort!

On currentBudget:

One of the things that is easy to tell you about is Python's context managers docs.

The context manager lets you write code in a different context and takes care of preparing that context and cleaning it up. In your case, there's a context to deal with opened files :)

So, instead of

def currentBudget():
    fileTransaction = open("transactions.csv", "r")
    info = fileTransaction.readlines()
    fileTransaction.close()
    # ...

it is recommended that you do

def currentBudget():
    with open("transactions.csv", "r") as f:
        info = fileTransaction.readlines()
    # ...

The context manager makes sure the file is properly closed even if the code raises an error. Generally, inside the with statement you write the least amount of code possible, so that the context can get cleaned up ASAP.

Also, if you are dealing with csv files you might want to take a look at the csv library Python provides: csv docs.


On organisation:

I really liked that you grouped related prints in functions to call repeatedly! One thing you might consider is factoring the different actions you take, depending on the userInput variable, into separate functions. That way, the body of your main function is cleaner and easier to read, and then you have a separate function for each functionality.

On user input:

Clever usage of .lower() to handle capitalised input ;)

You are doing relatively basic I/O, with the user just typing a single letter to pick an action. One thing you might want to do is

userInput = input("\nEnter your Choice: ").trim().lower()

This removes leading/trailing whitespace (with .trim). Additionally, you may want to also add [0] at the end of the line if it is acceptable for the user to write a whole word but you only need to use the first letter to distinguish. This doesn't make much sense while the actions are a), b), etc, but would make sense if you renamed the options to reflect what they actually do.

Good luck :)

\$\endgroup\$
5
  • \$\begingroup\$ Awesome :D Thank you so much, I'll start to incorporate that into my code in that case, I had no idea that is what the "with open" did. Thank you so much for your help!! \$\endgroup\$ – MJLz Apr 13 at 10:38
  • \$\begingroup\$ Anytime! Python is huge, and while people often use Python to glue many different libraries, they forget that core Python has plenty of useful and interesting features... The context managers being one of them :) I'll write about context managers in my blog soon, because I love them so much! \$\endgroup\$ – RGS Apr 13 at 10:41
  • \$\begingroup\$ Btw @JavierJose I updated the answer so be sure to check that. \$\endgroup\$ – RGS Apr 13 at 10:48
  • 1
    \$\begingroup\$ Ahhh you're amazing! Thank you so much honestly... I'll be incorporating all your feedback into the project 100%. I'll also check out your blog ;)! Thank you again for all the help and time. :) You make me want to code more ahaha \$\endgroup\$ – MJLz Apr 13 at 11:00
  • \$\begingroup\$ @JavierJose coding can be a lot of fun, yes ;) \$\endgroup\$ – RGS Apr 13 at 11:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.