๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
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๋กœ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์–ด ๋ˆ„๊ตฌ๋‚˜ ์„ค์น˜ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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


    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€