калькулятор python 3 с ткинтером - PullRequest
0 голосов
/ 21 сентября 2018

Я давно программирую.Только недавно я решил сделать удар в python (я должен работать с C #, потому что я учусь в нем, но меня не волнуют окна. Длинная история)

В любом случае, я был на этом сайтеи он показал источник для калькулятора.Я взял его, положил в PyCharm и начал учиться.К тому времени, когда я закончил, я значительно изменил источник.Я добавил привязку к клавиатуре и сократил много избыточного кода.

Мой вопрос прост, является ли этот код, который я написал, эффективным с точки зрения стандарта Python?

# -*-coding: utf-8-*-
# !/usr/bin/python3.5

from tkinter import Tk, Button, Entry, END
import math

class Calc:
    def getandreplace(self):  # replace x, + and % to symbols that can be used in calculations
        # we wont re write this to the text box until we are done with calculations

        self.txt = self.e.get() # Get value from text box and assign it to the global txt var
        self.txt = self.txt.replace('÷', '/')
        self.txt = self.txt.replace('x', '*')
        self.txt = self.txt.replace('%', '/100')

    def evaluation(self, specfunc):  # Evaluate the items in the text box for calculation specfunc = eq, sqroot or power
        self.getandreplace()
        try:
            self.txt = eval(str(self.txt))  # evaluate the expression using the eval function
        except SyntaxError:
            self.displayinvalid()
        else:
            if any([specfunc == 'sqroot', specfunc == 'power']):  # Square Root and Power are special
                self.txt = self.evalspecialfunctions(specfunc)

            self.refreshtext()

    def displayinvalid(self):
        self.e.delete(0, END)
        self.e.insert(0, 'Invalid Input!')

    def refreshtext(self):  # Delete current contents of textbox and replace with our completed evaluatioin
        self.e.delete(0, END)
        self.e.insert(0, self.txt)

    def evalspecialfunctions(self, specfunc):  # Calculate square root and power if specfunc is sqroot or power
        if specfunc == 'sqroot':
            return math.sqrt(float(self.txt))
        elif specfunc == 'power':
            return math.pow(float(self.txt), 2)

    def clearall(self): # AC button pressed on form or 'esc" pressed on keyboard
        self.e.delete(0, END)
        self.e.insert(0, '0')

    def clear1(self, event=None):
        # C button press on form or backspace press on keyboard event defined on keyboard press

        if event is None:
            self.txt = self.e.get()[:-1]  # Form backspace done by hand
        else:
            self.txt = self.getvalue()  # No need to manually delete when done from keyboard

            self.refreshtext()

    def action(self, argi: object):  # Number or operator button pressed on form and passed in as argi
        self.txt = self.getvalue()

        self.stripfirstchar()

        self.e.insert(END, argi)

    def keyaction(self, event=None):  # Key pressed on keyboard which defines event
        self.txt = self.getvalue()

        if event.char.isdigit():
            self.stripfirstchar()
        elif event.char in '/*-+%().':
            self.stripfirstchar()
        elif event.char == '\x08':
            self.clear1(event)
        elif event.char == '\x1b':
            self.clearall()
        elif event.char == '\r':
            self.evaluation('eq')
        else:
            self.displayinvalid()
            return 'break'

    def stripfirstchar(self):  # Strips leading 0 from text box with first key or button is pressed
        if self.txt[0] == '0':
            self.e.delete(0, 1)

    def getvalue(self):  # Returns value of the text box
        return self.e.get()

    def __init__(self, master):  # Constructor method
        self.txt = 'o'  # Global var to work with text box contents
        master.title('Calulator')
        master.geometry()
        self.e = Entry(master)
        self.e.grid(row=0, column=0, columnspan=6, pady=3)
        self.e.insert(0, '0')
        self.e.focus_set()  # Sets focus on the text box text area

        # Generating Buttons
        Button(master, text="=", width=10, command=lambda: self.evaluation('eq')).grid(row=4, column=4, columnspan=2)
        Button(master, text='AC', width=3, command=lambda: self.clearall()).grid(row=1, column=4)
        Button(master, text='C', width=3, command=lambda: self.clear1()).grid(row=1, column=5)
        Button(master, text="+", width=3, command=lambda: self.action('+')).grid(row=4, column=3)
        Button(master, text="x", width=3, command=lambda: self.action('x')).grid(row=2, column=3)
        Button(master, text="-", width=3, command=lambda: self.action('-')).grid(row=3, column=3)
        Button(master, text="÷", width=3, command=lambda: self.action('÷')).grid(row=1, column=3)
        Button(master, text="%", width=3, command=lambda: self.action('%')).grid(row=4, column=2)
        Button(master, text="7", width=3, command=lambda: self.action('7')).grid(row=1, column=0)
        Button(master, text="8", width=3, command=lambda: self.action('8')).grid(row=1, column=1)
        Button(master, text="9", width=3, command=lambda: self.action('9')).grid(row=1, column=2)
        Button(master, text="4", width=3, command=lambda: self.action('4')).grid(row=2, column=0)
        Button(master, text="5", width=3, command=lambda: self.action('5')).grid(row=2, column=1)
        Button(master, text="6", width=3, command=lambda: self.action('6')).grid(row=2, column=2)
        Button(master, text="1", width=3, command=lambda: self.action('1')).grid(row=3, column=0)
        Button(master, text="2", width=3, command=lambda: self.action('2')).grid(row=3, column=1)
        Button(master, text="3", width=3, command=lambda: self.action('3')).grid(row=3, column=2)
        Button(master, text="0", width=3, command=lambda: self.action('0')).grid(row=4, column=0)
        Button(master, text=".", width=3, command=lambda: self.action('.')).grid(row=4, column=1)
        Button(master, text="(", width=3, command=lambda: self.action('(')).grid(row=2, column=4)
        Button(master, text=")", width=3, command=lambda: self.action(')')).grid(row=2, column=5)
        Button(master, text="√", width=3, command=lambda: self.evaluation('sqroot')).grid(row=3, column=4)
        Button(master, text="x²", width=3, command=lambda: self.evaluation('power')).grid(row=3, column=5)

        # bind key strokes
        self.e.bind('<Key>', lambda evt: self.keyaction(evt))


# Main
root = Tk()
obj = Calc(root)  # object instantiated
root.mainloop()

Меня не волнуют имена некоторых имен функций и переменныхимена.Мне нравится использовать описательные имена, поэтому такие имена, как self.e, назывались бы self.textbox или что-то в этом роде.так что эти вещи - остатки от веб-копии, которую я нашел и не изменил их.

1 Ответ

0 голосов
/ 21 сентября 2018

Не совсем то, что нужно для обзоров кода, но я все равно собираюсь это сделать, потому что я жестоко откладываю.

Хороший код

Прежде всего, ваш код работает (я полагаю,), выглядит хорошо.Хороший код - это хороший код на любом языке.Некоторые люди зациклены на том, чтобы код был Pythonic, я не из тех людей.

Структурирование GUI

Код GUI отстой.Это повторяющееся, многословное, беспокойное и безобразное.Это не критика вашего кода, это комментарий ко всему коду графического интерфейса, кажется, что нет хорошего решения.Мы управляем этим, отделяя код GUI от всего остального.Существуют формальные подходы к этому, такие как Model-View-Controller и принципы, такие как разделение проблем.Ключ состоит в том, чтобы полностью отделить ваш уродливый хрупкий код GUI от реального кода, который вам небезразличен, чтобы мы могли попытаться забыть, насколько он уродлив.

Ваша реализация тесно связывает GUI с функциональностью.Это тривиальная проблема уровня, так что это не так уж плохо.Тем не менее, в качестве учебного упражнения вы должны разделить их и сделать «правильный» путь, начать с создания второго класса и переместить функцию оценки.

eval

Вторая важная вещь - этоиспользование функции eval.Это очень элегантно, преобразовать ввод в Python-совместимую математику и просто попросить Python дать вам ответ.Иными словами, вы берете пользовательский ввод, немного его фильтруете и выполняете прямо.С моим опытом в области безопасности это вызывает у меня дрожь.Не проблема для этой программы, вы выполняете локально, пользователь не может делать ничего, что он не может делать в обычном режиме.Но не делайте ничего подобного с онлайн-кодом.

main

Наконец, стандартная практика при объединении классов и кода, подобного этой, заключается в том, чтобы поместить код в условное выражение __main__.Это позволяет вам импортировать код в другое место для тестирования и т. Д. Следующая ссылка хорошо объясняет это:

...