Search code examples
pythontkinterpyinstallercompiler-optimization

How to optimize a compiled application from Python


I wrote a small calculator and decided to try creating an EXE and APK file. I have a question: why did the file size increase so much after compiling it into an EXE, and it seems to be loading something when launched? In general, how can I optimize it?

I'm doing this out of scientific curiosity, so please explain it to me in simpler terms. I might be mistaken in my terminology, so feel free to correct me. I hope this text is sufficient so that I don't have to write more.

I compiled it using auto-py-to-exe.

from tkinter import *
import tkinter.font as tkFont


def button_click(number):
    current = entry.get()
    entry.delete(0, END)
    entry.insert(0, str(current) + str(number))

def button_clear():
    entry.delete(0, END)

def button_clear_number():
     current = entry.get()
     entry.delete(0, END)
     entry.insert(0, str(current[:-1]))

def button_equal(event=0):
    try:
        number = entry.get()
        entry.delete(0, END)
        if number:
            result = eval(f"{number}")
            entry.insert(0, result)
    except:
        entry.insert(0, number)
        print("Error")


root = Tk()
root.title("Калькулятор")
root.configure(bg='gray')
root.resizable(False, False)

pixel = PhotoImage(width=50, height=50)

valide_key = ["1","2","3","4","5","6","7","8","9","0",".","+","-","*","/","(",")"]

# функция для проверки ввода
def validate_entry(text):
    if all(char in valide_key for char in text) or text == "":
        return True
    else:
        return False

entry = Entry(root, width=15, font=tkFont.Font(size=20), validate="key", validatecommand=(root.register(validate_entry), "%S"))
entry.grid(row=0, column=0, columnspan=4)
entry.focus_set()
entry.bind("<Return>", button_equal)

buttons = [
    ("7", 3, 0),
    ("8", 3, 1),
    ("9", 3, 2),
    ("4", 4, 0),
    ("5", 4, 1),
    ("6", 4, 2),
    ("1", 5, 0),
    ("2", 5, 1),
    ("3", 5, 2),
    ("0", 6, 0),
    (".", 6, 1),
    ("+", 6, 3),
    ("-", 5, 3),
    ("*", 4, 3),
    ("/", 3, 3),
    ("(", 2, 0),
    (")", 2, 1)
]

for button_text, row, column in buttons:
    button = Button(root,image=pixel,compound="c", text=button_text, command=lambda text=button_text: button_click(text))
    button.grid(row=row, column=column)

clear_button = Button(root,image=pixel,compound="c", text="C",  command=button_clear)
clear_button.grid(row=2, column=2)

clear_number = Button(root,image=pixel,compound="c", text="<",  command=button_clear_number)
clear_number.grid(row=2, column=3)

equal_button = Button(root,image=pixel,compound="c", text="=",  command=button_equal)
equal_button.grid(row=6, column=2)

root.mainloop()

Program


Solution

  • When you use auto-py-to-exe (which is using pyinstaller under the hood) to create an executable, that executable will necessarily have tkinter and a Python interpreter bundled with it (along with whatever other dependencies it needs). Your application's main *.py file may be small, but the code required to support / run it is not.

    You can get your executable's overall size down by not using the --onefile option, but that ends up making it less portable since its dependencies now exist separately from the *.exe itself.

    EDIT: To clarify, tkinter will be bundled if you've made a tkinter app...it's not always included.