본문 바로가기
IT 이것저것/파이썬python

파이썬 기초 배우기: 간단한 가계부 및 비용 추적기를 코딩 해 보기

by KaNonx카논 2025. 2. 4.
반응형

파이썬 기초 배우기: 간단한 가계부 및 비용 추적기를 코딩 해 보기

예산을 세워본 적이 있다면, 원하는 일을 하는 비용 추적기를 구하는 것이 얼마나 어려울 수 있는지 알고 계실 겁니다. 하지만 직접 만들어보는 건 어떨까요? 실제로 사용할 수 있는 간단한 비용 추적기를 만들어 Python 기본 사항을 배워보겠습니다.

비용 추적 앱의 요구 사항 정의

이 아이디어를 떠올렸을 때, 저는 단순한 다른 명령줄 터미널 앱 이상의 앱을 만들고 싶었습니다. 우리는 파이썬을 사용한 간단한 할 일 목록과 같은 몇 가지를 만들었습니다. 이번에는 GUI를 사용하고 싶어서 사용 가능한 UI 요소를 얻기 위해 Tkinter 라이브러리를 가져오기로 결정했습니다.

라이브러리를 통해 코드를 재사용할 수 있습니다. 보통 파이썬으로 대부분의 작업을 수행할 수 있는 라이브러리가 있습니다. 가져오기를 하면 포함된 모든 코드를 처음부터 다시 쓰는 것을 피할 수 있습니다.

이 앱에서는 다음을 구현할 것입니다:

  • 비용 항목
  • 예산 정의
  • 예산 대비 지출 비교하기
  • 지출 내역 보기

이 작업이 끝나면 파이썬이 어떻게 작동하는지에 대한 적절한 아이디어를 얻을 수 있을 것이며, 첫 번째 GUI 기반 파이썬 앱을 완성할 수 있을 것입니다.

프로젝트 설정

Python 버전을 확인하여 기기에 Python이 설치되어 있는지 확인해야 합니다. 이미 제가 좋아하는 IDE(Visual Studio)를 파이썬에 연결하는 방법을 다루었습니다. 기기에 Python을 설치하고 최신 버전으로 업데이트하는 오버헤드를 해결한 후, 새 프로젝트를 만드는 것부터 시작할 수 있습니다.

 프로젝트를 위해 파이썬을 선택한 이유는 초보자들에게 가장 쉬운 언어 중 하나이기 때문입니다. 비용 추적기 구축에 대해 알아봅시다!

메인 애플리케이션 창 구축

이 애플리케이션의 터미널에서 멀어질 예정이므로 대신 애플리케이션의 그래픽 사용자 인터페이스(GUI)를 구축하기 위해 Tkinter를 설정해야 합니다. 파이썬의 UI 디자인은 복잡할 수 있으므로 단순하게 유지하고 제가 제공하는 코드가 무엇을 하는지 알려드리겠습니다. 제 UI 창은 이렇게 정의될 것입니다. 먼저 Tkinter를 가져오는 것부터 시작하겠습니다:

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog

Tkinter에는 기본 UI를 만드는 데 필요한 모든 기능이 포함되어 있습니다. Tkinter 내부의 테마 엔진인 Ttk도 수입하고 있다는 것을 알게 될 것입니다. 이를 통해 원하는 경우 UI의 모양을 제어할 수 있습니다. 또한 사용자에게 초기 예산 설정을 요청하기 위해 메시지 상자와 간단한 대화 상자를 사용할 예정입니다. 또한 향후 액세스를 원할 경우를 대비하여 월별 데이터를 저장할 수 있기를 원하므로 파일 상단에 추가할 예정입니다:

import json
from datetime import datetime

제 이름과 매우 가까운 것 외에도 JSON은 사실 직렬화 시스템으로서 꽤 멋진 편입니다. 다행히도 Python에는 기본으로 제공되므로 직접 가져올 수 있습니다. datetime 가져오기는 애플리케이션 전체에서 날짜를 올바르게 형식화하는 데 도움이 됩니다.

이제 수입품을 파악했으니 실제로 창을 만들어 보겠습니다:

def create_widgets(self):
    # Main Frame
    main_frame = ttk.Frame(self.root, padding="10")
    main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

    # Expense Input Frame
    input_frame = ttk.LabelFrame(main_frame, text="Add Expense", padding="10")
    input_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)

    ttk.Label(input_frame, text="Date (YYYY-MM-DD):").grid(row=0, column=0, sticky=tk.W)
    self.date_entry = ttk.Entry(input_frame)
    self.date_entry.grid(row=0, column=1, padx=5, pady=2)

    ttk.Label(input_frame, text="Category:").grid(row=1, column=0, sticky=tk.W)
    self.category_combobox = ttk.Combobox(input_frame, values=self.categories)
    self.category_combobox.grid(row=1, column=1, padx=5, pady=2)

    ttk.Label(input_frame, text="Amount:").grid(row=2, column=0, sticky=tk.W)
    self.amount_entry = ttk.Entry(input_frame)
    self.amount_entry.grid(row=2, column=1, padx=5, pady=2)

    ttk.Button(input_frame, text="Add Expense", command=self.add_expense).grid(row=3, column=0, columnspan=2, pady=5)

    # Category Management Frame
    category_frame = ttk.LabelFrame(main_frame, text="Manage Categories", padding="10")
    category_frame.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)

    self.new_category_entry = ttk.Entry(category_frame)
    self.new_category_entry.grid(row=0, column=0, padx=5, pady=2)
    ttk.Button(category_frame, text="Add Category", command=self.add_category).grid(row=0, column=1, padx=5, pady=2)

이 항목들은 단지 우리의 창을 스타일링하고 있을 뿐입니다. 원한다면 숫자를 가지고 놀면서 숫자를 만지작거리는 것은 무해하기 때문에 (마지막 창이 끔찍해 보이는 것 외에는) 어떤 결과가 나오는지 확인할 수 있습니다. 프레임과 저장 버튼을 표시하고 그리드가 멋지게 보이도록 구성해야 합니다:

 # Display Frame
 display_frame = ttk.LabelFrame(main_frame, text="Expenses and Budget", padding="10")
 display_frame.grid(row=0, column=1, rowspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), padx=5, pady=5)

 self.expense_tree = ttk.Treeview(display_frame, columns=('Date', 'Category', 'Amount'), show='headings')
 self.expense_tree.heading('Date', text='Date')
 self.expense_tree.heading('Category', text='Category')
 self.expense_tree.heading('Amount', text='Amount')
 self.expense_tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

 scrollbar = ttk.Scrollbar(display_frame, orient=tk.VERTICAL, command=self.expense_tree.yview)
 scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
 self.expense_tree.configure(yscrollcommand=scrollbar.set)

 self.budget_label = ttk.Label(display_frame, text=f"Monthly Budget: ${self.monthly_budget:.2f}")
 self.budget_label.grid(row=1, column=0, sticky=tk.W, pady=2)

 self.total_expenses_label = ttk.Label(display_frame, text="Total Expenses: $0.00")
 self.total_expenses_label.grid(row=2, column=0, sticky=tk.W, pady=2)

 self.remaining_budget_label = ttk.Label(display_frame, text=f"Remaining Budget: ${self.monthly_budget:.2f}")
 self.remaining_budget_label.grid(row=3, column=0, sticky=tk.W, pady=2)

 # Save Button
 ttk.Button(display_frame, text="Save Data", command=self.save_data).grid(row=4, column=0, pady=10)

 # Configure grid
 self.root.columnconfigure(0, weight=1)
 self.root.rowconfigure(0, weight=1)
 main_frame.columnconfigure(1, weight=1)
 main_frame.rowconfigure(0, weight=1)
 display_frame.columnconfigure(0, weight=1)
 display_frame.rowconfigure(0, weight=1)

보시다시피, UI는 제대로 작동하기 위해 많은 코딩이 필요합니다. 하지만 파이썬 기초를 배울 계획이므로 UI 디자인을 이해하는 것도 중요합니다. 이제 UI를 실행했으니 기능에 대해 작업해 보겠습니다.

카테고리 정의 및 비용 추가

앱에 약간의 '바디'를 부여하기 위해 몇 가지 비용 카테고리를 미리 정의했습니다. 나머지 정의와 함께 헤더로 포함시켰습니다:

class ExpenseTrackerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Expense Tracker & Budget Planner")
        self.root.geometry("1100x500")

        self.expenses = []
        self.categories = ["Rent", "Food", "Entertainment", "Car", "Credit Cards"]
        
        self.monthly_budget = self.get_initial_budget()
        
        self.create_widgets()

    def get_initial_budget(self):
        while True:
            budget = simpledialog.askfloat("Monthly Budget", "Enter your monthly budget:", minvalue=0.01)
            if budget is not None:
                return budget
            else:
                if messagebox.askyesno("No Budget", "You haven't entered a budget. Do you want to exit?"):
                    self.root.quit()
                    return 0

이와 같은 정의는 우리 프로그램의 최상위에 있어야 합니다. 이를 위해 이 스니펫은 이미 개발한 위젯 생성 코드보다 먼저 제공되어야 합니다.

get_initial_budget(자체) 기능은 앱 실행 시작 시 팝업을 생성하여 사용 가능한 금액을 결정하는 데이터를 수집합니다. 값을 입력하지 않으면 앱이 즉시 종료됩니다.

우리는 또한 새로운 맞춤형 항목으로 비용을 추가하고 카테고리를 업데이트할 수 있는 기능이 필요합니다. 다행히도 이것은 구현하기도 간단합니다:

def add_expense(self):
    try:
        date = self.date_entry.get()
        category = self.category_combobox.get()
        amount = float(self.amount_entry.get())

        self.expenses.append({
            'date': date,
            'category': category,
            'amount': amount
        })

        self.update_expense_list()
        self.update_budget_info()
        self.clear_input_fields()
    except ValueError:
        messagebox.showerror("Error", "Invalid input. Please check your entries.")

def add_category(self):
    new_category = self.new_category_entry.get().strip()
    if new_category and new_category not in self.categories:
        self.categories.append(new_category)
        self.category_combobox['values'] = self.categories
        self.new_category_entry.delete(0, tk.END)
        messagebox.showinfo("Category Added", f"'{new_category}' has been added to the categories.")
    else:
        messagebox.showerror("Error", "Invalid category name or category already exists.")

기본 기능을 정리하려면 새로운 비용을 입력할 때 비용 목록을 업데이트하는 기능이 필요합니다. 데이터를 입력한 후 콤보 상자를 지우려면 도우미 기능이 필요합니다. 마지막으로, 우리는 아직 사용 가능한 예산의 양을 계산해야 할 것입니다. 이 간단한 코드 조각은 우리가 그것을 할 수 있게 해줄 것입니다:

def update_expense_list(self):
    for item in self.expense_tree.get_children():
        self.expense_tree.delete(item)
    for expense in self.expenses:
        self.expense_tree.insert('', 'end', values=(
            expense['date'],
            expense['category'],
            f"${expense['amount']:.2f}"
        ))

def update_budget_info(self):
    total_expenses = sum(expense['amount'] for expense in self.expenses)
    remaining_budget = self.monthly_budget - total_expenses

    self.total_expenses_label.config(text=f"Total Expenses: ${total_expenses:.2f}")
    self.remaining_budget_label.config(text=f"Remaining Budget: ${remaining_budget:.2f}")

def clear_input_fields(self):
    self.date_entry.delete(0, tk.END)
    self.category_combobox.set('')
    self.amount_entry.delete(0, tk.END)

그렇다면 이 모든 데이터를 입력한 후, 어떻게 하면 손실되지 않도록 보장할 수 있을까요? 이전에 가져온 JSON 형식을 사용하여 간단한 저장 기능을 구현했습니다:

def save_data(self):
    data = {
        'budget': self.monthly_budget,
        'categories': self.categories,
        'expenses': self.expenses
    }
    
    # Get the current date to use in the filename
    current_date = datetime.now().strftime("%Y-%m")
    default_filename = f"expense_data_{current_date}.json"
    
    file_path = filedialog.asksaveasfilename(
        defaultextension=".json",
        filetypes=[("JSON files", "*.json")],
        initialfile=default_filename
    )
    
    if file_path:
        with open(file_path, 'w') as f:
            json.dump(data, f, indent=2)
        messagebox.showinfo("Save Successful", f"Data saved to {file_path}")

이 함수는 데이터를 직렬화하여 파일 이름에 현재 날짜가 추가된 특정 파일 위치에 저장합니다. 마지막으로 해야 할 일은 메인() 함수 루프를 구성하는 것입니다:

if __name__ == "__main__":
    root = tk.Tk()
    app = ExpenseTrackerApp(root)
    root.mainloop()

그렇게 하면 우리의 비용 추적기가 문제 없이 작동할 수 있을 것입니다. 파이썬에서 첫 번째 GUI 기반 애플리케이션을 완료하신 것을 축하드립니다!

추가, 단점 및 맞춤 설정

이 작업을 완료한 후, Tkinter가 어떻게 작동하는지와 GUI 생성에 어떻게 사용할 수 있는지에 대해 조금 이해하게 됩니다. CSS나 그래픽 디자인에 대해 조금 알고 있다면, Tkinter를 빠르게 사용하는 방법을 알아낼 수 있을 것입니다. 몇 가지 도전 과제가 필요하다면 다음에 시도해 볼 수 있습니다:

  • 앱에 새로운 테마를 만들거나 사용하세요.
  • "로드" 기능과 버튼을 생성합니다. 더 많은 탐험 공간을 제공하기 위해 로드 함수를 제외했습니다.
  • 그래픽 기반 예산 내역을 파이 차트로 분석하는 방법을 살펴보세요.

최종 애플리케이션은 현재 다음과 같은 모습이어야 합니다:

여기서 어디로 가야 할까요?

이 개발 튜토리얼은 Tkinter에 대한 광범위한 개요만 제공했지만, 더 많은 GUI 기반 앱을 만들 계획이라면 Tkinter가 무엇을 할 수 있는지 더 잘 이해해야 합니다. RealPython은 Tkinter 또는 기타 사용 가능한 GUI 프레임워크나 툴킷을 사용하는 방법에 대한 아이디어를 제공할 수 있습니다. 파이썬은 기본적으로 이해하기 쉽지만, 파이썬의 기초를 배우면서 탐구할 수 있는 것이 너무 많습니다. 당신이 창조할 수 있는 것을 제한하는 유일한 것은 상상력입니다.

 

 

-

반응형

댓글