๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Lect & Tip/Python

์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๋ฐฉ๋ฒ•, ํŒŒ์ด์ฌ ์ž๋™ ๊ณ„์‚ฐ๊ธฐ ๋งŒ๋“ค๊ธฐ

by st๊ณต๊ฐ„ 2025. 4. 25.
๋ฐ˜์‘ํ˜•

์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๋ฐฉ๋ฒ•, ํŒŒ์ด์ฌ ์ผ์šฉ์ง ์†Œ๋“์„ธ ์ž๋™ ๊ณ„์‚ฐ๊ธฐ ๋งŒ๋“ค๊ธฐ

์ผ์šฉ์ง ๊ทผ๋กœ์ž๋Š” ์›”๊ธ‰์ œ๊ฐ€ ์•„๋‹Œ ์ผ๊ธ‰์—ฌ × ๊ทผ๋ฌด์ผ์ˆ˜๋กœ ์†Œ๋“์ด ๊ฒฐ์ •๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋งค๋ฒˆ ์ง€๊ธ‰ ์‹œ ์›์ฒœ์ง•์ˆ˜์„ธ์•ก์„ ์ •ํ™•ํžˆ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ˆ˜์ž‘์—…์œผ๋กœ ๊ณ„์‚ฐํ•˜๋‹ค ๋ณด๋ฉด ์‹ค์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๊ฐ„๋‹จํ•œ ํŒŒ์ด์ฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ์„ธ์•ก์„ ์‚ฐ์ถœํ•˜๋ฉด ์—…๋ฌด ํšจ์œจ์„ฑ๊ณผ ์ •ํ™•์„ฑ์„ ๋™์‹œ์— ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๋ฐฉ๋ฒ•์œผ๋กœ ๋ณธ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๊ธฐ๋ฅผ ํŒŒ์ด์ฌ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ณ , PyInstaller๋ฅผ ์ด์šฉํ•ด exe ํŒŒ์ผ๋กœ ๋ฐฐํฌํ•˜๋Š” ๋ฐฉ๋ฒ•๊นŒ์ง€ ๋‹จ๊ณ„๋ณ„๋กœ ์•ˆ๋‚ด๋“œ๋ฆฝ๋‹ˆ๋‹ค.


์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๋ฐฉ๋ฒ• ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ๋ฐ ์ค€๋น„์‚ฌํ•ญ

์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๋ฐฉ๋ฒ•

Python ์„ค์น˜

  • ๊ณต์‹ ํ™ˆํŽ˜์ด์ง€(python.org)์—์„œ Python 3.8 ์ด์ƒ ๋ฒ„์ „์„ ์„ค์น˜ํ•ด ์ฃผ์„ธ์š”.
  • ์„ค์น˜ ์‹œ “Add Python to PATH” ์˜ต์…˜์„ ์ฒดํฌํ•ด์•ผ ํ„ฐ๋ฏธ๋„(๋˜๋Š” ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ)์—์„œ ๋ฐ”๋กœ python ๋ช…๋ น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

daily_tax_gui.exe
9.78MB

ํ•„์š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • ๋ณธ ์˜ˆ์ œ๋Š” ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ๋ณ„๋„์˜ ํŒจํ‚ค์ง€ ์„ค์น˜๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.
  • exe ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ PyInstaller๋งŒ ์ถ”๊ฐ€๋กœ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.
pip install pyinstaller

์—๋””ํ„ฐ ๋ฐ ์‹คํ–‰ ํ™˜๊ฒฝ

  • ์ฝ”๋“œ ์ž‘์„ฑ์€ VS Code, PyCharm, Sublime Text ๋“ฑ ํŽธํ•œ ํŽธ์ง‘๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ํ„ฐ๋ฏธ๋„(cmd, PowerShell, bash)์—์„œ python tax_calculator.py ๋ช…๋ น์œผ๋กœ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ์šฉ์ง ์†Œ๋“์„ธ ์ž๋™ ๊ณ„์‚ฐ๊ธฐ ์ „์ฒด ์†Œ์Šค์ฝ”๋“œ

import tkinter as tk
from tkinter import messagebox

def calculate_tax():
    """
    1. ๊ณผ์„ธ์†Œ๋“๊ธˆ์•ก = max(์ผ๊ธ‰์—ฌ - 150,000์›, 0)
    2. ์‚ฐ์ถœ์„ธ์•ก = ๊ณผ์„ธ์†Œ๋“๊ธˆ์•ก * 6%
    3. ๊ฒฐ์ •์„ธ์•ก = ์‚ฐ์ถœ์„ธ์•ก * (1 - 55%)
    4. ์›์ฒœ์ง•์ˆ˜์„ธ์•ก = ๊ฒฐ์ •์„ธ์•ก * 1.1 (์ง€๋ฐฉ์†Œ๋“์„ธ ํฌํ•จ)
    """
    try:
        daily_wage = int(entry_wage.get())
        # 1. ๊ณผ์„ธ์†Œ๋“๊ธˆ์•ก
        taxable_income = max(daily_wage - 150_000, 0)
        # 2. ์‚ฐ์ถœ์„ธ์•ก
        basic_tax = taxable_income * 0.06
        # 3. ๊ฒฐ์ •์„ธ์•ก
        final_tax = basic_tax * (1 - 0.55)
        # 4. ์ง€๋ฐฉ์†Œ๋“์„ธ ํฌํ•จ
        withholding_tax = round(final_tax * 1.1)

        label_result.config(text=f"์›์ฒœ์ง•์ˆ˜์„ธ์•ก: {withholding_tax}์›")
    except ValueError:
        messagebox.showerror("์ž…๋ ฅ ์˜ค๋ฅ˜", "์ผ๊ธ‰์—ฌ์—๋Š” ์ˆซ์ž๋งŒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.")

# ๋ฉ”์ธ ์œˆ๋„์šฐ ์„ค์ •
root = tk.Tk()
root.title("์ผ์šฉ์ง ์†Œ๋“์„ธ ๊ณ„์‚ฐ๊ธฐ")
root.geometry("320x180")
root.resizable(False, False)

# ์ž…๋ ฅ ํ”„๋ ˆ์ž„
frame = tk.Frame(root, padx=10, pady=10)
frame.pack(fill="both", expand=True)

# ์œ„์ ฏ ๋ฐฐ์น˜
tk.Label(frame, text="์ผ๊ธ‰์—ฌ(์›):").grid(row=0, column=0, sticky="e")
entry_wage = tk.Entry(frame)
entry_wage.grid(row=0, column=1, pady=5)

btn_calc = tk.Button(frame, text="๊ณ„์‚ฐํ•˜๊ธฐ", width=20, command=calculate_tax)
btn_calc.grid(row=1, column=0, columnspan=2, pady=10)

label_result = tk.Label(frame, text="์›์ฒœ์ง•์ˆ˜์„ธ์•ก: ", font=("๋ง‘์€ ๊ณ ๋”•", 10, "bold"))
label_result.grid(row=2, column=0, columnspan=2)

# ์‹คํ–‰
root.mainloop()

exe ์ปดํŒŒ์ผ ๋ฐฉ๋ฒ•

PyInstaller ์„ค์น˜

pip install pyinstaller

๋‹จ์ผ ํŒŒ์ผ exe๋กœ ๋ฌถ๊ธฐ

  1. ํ„ฐ๋ฏธ๋„์—์„œ ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ์žˆ๋Š” ํด๋”๋กœ ์ด๋™
  2. ์•„๋ž˜ ๋ช…๋ น ์‹คํ–‰
    pyinstaller --onefile tax_calculator.py
  3. dist ํด๋” ์•ˆ์— tax_calculator.exe ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
  4. ์ƒ์„ฑ๋œ exe ํŒŒ์ผ์„ ๋”๋ธ”ํด๋ฆญํ•˜๊ฑฐ๋‚˜,
    ./dist/tax_calculator.exe
    ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฐํฌ ํŒ

  • --name ์˜ต์…˜์œผ๋กœ exe ํŒŒ์ผ๋ช…์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    pyinstaller --onefile --name ์ผ์šฉ์ง์„ธ๊ธˆ๊ณ„์‚ฐ๊ธฐ tax_calculator.py
  • ์•„์ด์ฝ˜(.ico) ํŒŒ์ผ์„ ์ง€์ •ํ•˜๋ ค๋ฉด --icon=myicon.ico ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

PyInstaller ์ปดํŒŒ์ผ ์—๋Ÿฌ(UnicodeDecodeError) ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

6364 INFO: Analyzing D:\WorkPY\CalcTax_nogada\calculate_daily_tax.py
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Scripts\pyinstaller.exe\__main__.py", line 7, in <module>
    sys.exit(_console_script_run())
             ~~~~~~~~~~~~~~~~~~~^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\__main__.py", line 231, in _console_script_run
    run()
    ~~~^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\__main__.py", line 215, in run
    run_build(pyi_config, spec_file, **vars(args))
    ~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\__main__.py", line 70, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\building\build_main.py", line 1270, in main
    build(specfile, distpath, workpath, clean_build)
    ~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\building\build_main.py", line 1208, in build
    exec(code, spec_namespace)
    ~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "D:\WorkPY\CalcTax_nogada\calculate_daily_taxGUI.spec", line 4, in <module>
    a = Analysis(
        ['calculate_daily_tax.py'],
    ...<9 lines>...
        optimize=0,
    )
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\building\build_main.py", line 582, in __init__
    self.__postinit__()
    ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\building\datastruct.py", line 184, in __postinit__
    self.assemble()
    ~~~~~~~~~~~~~^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\building\build_main.py", line 712, in assemble
    program_scripts.append(self.graph.add_script(script))
                           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\depend\analysis.py", line 283, in add_script
    self._top_script_node = super().add_script(pathname)
                            ~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "C:\Users\hidec\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\lib\modulegraph\modulegraph.py", line 1170, in add_script
    contents = importlib.util.decode_source(contents)
  File "<frozen importlib._bootstrap_external>", line 825, in decode_source
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 64: invalid start byte

์ปดํŒŒ์ผ ์ค‘ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 64: invalid start byte

์›์ธ

  • ์†Œ์Šค ํŒŒ์ผ์ด UTF-8์ด ์•„๋‹Œ ๋‹ค๋ฅธ ์ธ์ฝ”๋”ฉ(CP949, ANSI ๋“ฑ)์œผ๋กœ ์ €์žฅ๋˜์–ด ์žˆ์–ด PyInstaller๊ฐ€ ๋””์ฝ”๋”ฉ์— ์‹คํŒจํ•จ.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

  1. ์ธ์ฝ”๋”ฉ ์„ ์–ธ ์ถ”๊ฐ€
    • ์ฝ”๋“œ ์ตœ์ƒ๋‹จ์— # -*- coding: utf-8 -*-๋ฅผ ๋„ฃ์–ด ์ธ์ฝ”๋”ฉ์„ ๋ช…์‹œ
  2. ํŒŒ์ผ ์ธ์ฝ”๋”ฉ์„ UTF-8๋กœ ๋ณ€ํ™˜
    • VS Code: ์šฐ์ธก ํ•˜๋‹จ ์ธ์ฝ”๋”ฉ ๋ถ€๋ถ„ ํด๋ฆญ → “Save with Encoding” → “UTF-8” ์„ ํƒ
    • Notepad++: ์ธ์ฝ”๋”ฉ ๋ฉ”๋‰ด → “UTF-8๋กœ ๋ณ€ํ™˜” → ์ €์žฅ
  3. ๋‹ค์‹œ ์ปดํŒŒ์ผ
pyinstaller --onefile tax_calculator.py

  • ํŒŒ์ผ ์ธ์ฝ”๋”ฉ์„ UTF-8๋กœ ํ†ต์ผํ•˜๊ณ ,
  • # -*- coding: utf-8 -*- ์„ ์–ธ์„ ์ถ”๊ฐ€ํ•˜๋ฉด PyInstaller ์ปดํŒŒ์ผ ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์œ„ ๊ณผ์ •์„ ๊ฑฐ์น˜๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์„ค์น˜ ์—†์ด ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ EXE ํ˜•ํƒœ๋กœ ์ผ์šฉ์ง ์„ธ๊ธˆ ๊ณ„์‚ฐ๊ธฐ๋ฅผ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

์˜ค๋Š˜์€ ํŒŒ์ด์ฌ์œผ๋กœ ์ผ์šฉ์ง ๊ทผ๋กœ์ž์˜ ์›์ฒœ์ง•์ˆ˜์„ธ์•ก์„ ์ž๋™์œผ๋กœ ๊ณ„์‚ฐํ•˜๋Š” ์„ธ๊ธˆ ๊ณ„์‚ฐ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

  • ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜ ๊ตฌ์กฐ๋กœ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•˜๊ณ ,
  • PyInstaller๋ฅผ ํ™œ์šฉํ•ด ์œˆ๋„์šฐ์šฉ exe๋กœ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์–ด ๋ˆ„๊ตฌ๋‚˜ ์„ค์น˜ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธ์‚ฌ·๋…ธ๋ฌด ๋‹ด๋‹น์ž๋ผ๋ฉด ์ด ๊ณ„์‚ฐ๊ธฐ๋ฅผ ํ™œ์šฉํ•ด ์ผ์šฉ์ง ์„ธ์•ก ์‚ฐ์ถœ ์—…๋ฌด๋ฅผ ํฌ๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€