Калькулятор на Python принимает строку ввода


Он принимает строку ввода, как '1+1' вместо num1 = 1, num2 = 2, operation = '+' или что-то подобное.

def Numbers(var):
    return var == '0' or var == '1' or var == '2' or var == '3' or var == '4' or var == '5' or var == '6' or var == '7' or var == '8' or var == '9'

def Test4Num(varstr):
    n = 0
    var = ''
    try: 
        while Numbers(varstr[n]):
            var += varstr[n]
            n += 1
    except: pass
    return (int(var), n)

def operation(string, num1, num2):
    if string == '+':
        return num1 + num2
    if string == '-':
        return num1-num2
    if string == '*':
        return num1*num2
    if string == '/':
        return num1/num2
    if string == '^':
        return num1 ** num2

def operator(operato):
    return operato == '+' or operato == '-' or operato == '*' or operato == '/' or operato == '^'


negate = False
char = input('')

print(char + '=')
while True:
    try: 
        if char[0] == '-': #for negative numbers
            negate = True #because here the numbers are string format
            char = char[1:]
        number1 = Test4Num(char)[0]
        if negate == True:
            number1 = -number1
            negate = False
        end_number1 = Test4Num(char)[1]
        char = char[end_number1:]
        if char == '':
            print(number1)
            break
        op = char[0]
        char = char[1:]
        number2 = Test4Num(char)[0]
        end_number2 = Test4Num(char)[1]
        result = operation(op, number1, number2)
        number1 = result
        char = str(number1) + char[end_number2:]
        print(char)
    except: break
#created by Estoria Wandertag, while he was sitting on the toilet and thought about life and programming

Этот код является довольно простым, я имею в виду не использовать класс, любой импорт и т. д. (ок, он может просто использовать 5 основных операций в математике, но это выдвижная) и хотя это легко, я не нашел его в инете... Так вот почему я хотел бы поделиться этим. Если у вас есть идеи, пожалуйста, поделитесь ими. Я новичок здесь, и я не использовал Python для очень долго, так что есть много вещей, чтобы добавить, я думаю. (Извините за мой ужасный английский, я немец)



Комментарии
3 ответа

На другой очень хорошие ответы:

Организация кода и тестов

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

Это делает код легче понять, проще повторно использовать и более проверяемым.

Кроме того, это хорошая привычка, чтобы поместить ваш код на самом деле вызывается логика позади if __name__ == "__main__": охранник.

Все это учитывается, у вас есть:

def eval_math_expr(expr):
negate = False
while True:
try:
if expr[0] == '-': #for negative numbers
negate = True #because here the numbers are string format
expr = expr[1:]
number1 = Test4Num(expr)[0]
if negate == True:
number1 = -number1
negate = False
end_number1 = Test4Num(expr)[1]
expr = expr[end_number1:]
if expr == '':
return number1
op = expr[0]
expr = expr[1:]
number2 = Test4Num(expr)[0]
end_number2 = Test4Num(expr)[1]
result = operation(op, number1, number2)
number1 = result
expr = str(number1) + expr[end_number2:]
except Exception as e:
print(e)
break
return number1

if __name__ == '__main__':
interactive = False
if interactive:
expr = input('Enter your expression:')
print(expr + '=')
print(eval_math_expr(expr))
else:
for expr, res in {"2": 2, "2*4": 8, "4+8": 12, "100/3": 33, "2^3": 8}.items():
result = eval_math_expr(expr)
if res != result:
print("Computing", expr, "got", result, "instead of", res)

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

Кстати, ничего, кроме (без явных поймали тип исключения) и игнорируются исключения, как правило, с неодобрением, как они делают отладку очень больно.

Именования

Ваши имена функций не очень хорошо. Ваш может определить is_digit, get_number, perform_operation.

Упростить is_digit функция

Лучшая структура данных для проверки необходимо выполнить набор.
Вы могли бы написать что-то вроде:

DIGITS = set('0123456789')

def is_digit(var):
return var in DIGITS

Упростить perform_operation

Лучшая структура данных для логики, которую вы хотите выполнить это словарь операторов сопоставления функций.

import operator

OPERATIONS = {
'+' : operator.add,
'-' : operator.sub,
'*' : operator.mul,
'/' : operator.floordiv,
'^' : operator.pow,
}

def perform_operation(string, num1, num2):
op = OPERATIONS.get(string, None)
if op is not None:
return op(num1, num2)
else:
return None # How to handle this?

Примечание: использование floordiv вместо truediv устраняет проблему, нашли с тесты, описанные выше.

Упростить get_number

В Python, вы обычно не нужно сделать элементы из объекта по индексу. Что вы хотите, как правило для перебора различных элементов. Я настоятельно рекомендую читать/смотреть Нэд Батчелдер говорить называемая "петля как родной". В вашем случае, вы могли бы написать что-то вроде:

def get_number(varstr):
s = ""
for c in varstr:
if not is_digit(c):
break
s += c
return (int(s), len(s))

Используя кортеж распаковка

Как уже сказал, Вы могли бы использовать number1, end_number1 = get_number(expr) для вызова get_number только один раз.

На этом этапе код выглядит как:

import operator

DIGITS = set('0123456789')
OPERATIONS = {
'+' : operator.add,
'-' : operator.sub,
'*' : operator.mul,
'/' : operator.floordiv,
'^' : operator.pow,
}

def is_digit(var):
return var in DIGITS

def get_number(varstr):
s = ""
for c in varstr:
if not is_digit(c):
break
s += c
return (int(s), len(s))

def perform_operation(string, num1, num2):
op = OPERATIONS.get(string, None)
if op is not None:
return op(num1, num2)
else:
return None # How to handle this?

def eval_math_expr(expr):
negate = False
while True:
try:
if expr[0] == '-': #for negative numbers
negate = True #because here the numbers are string format
expr = expr[1:]
number1, end_number1 = get_number(expr)
expr = expr[end_number1:]
if negate == True:
number1 = -number1
negate = False
if expr == '':
return number1
op = expr[0]
expr = expr[1:]
number2, end_number2 = get_number(expr)
result = perform_operation(op, number1, number2)
number1 = result
expr = str(number1) + expr[end_number2:]
except Exception as e:
print(e)
break
return number1

if __name__ == '__main__':
interactive = False
if interactive:
expr = input('Enter your expression:')
print(expr + '=')
print(eval_math_expr(expr))
else:
for expr, res in {"2": 2, "2*4": 8, "4+8": 12, "100/3": 33, "2^3": 8, "-2": -2, "-2-3": -5}.items():
result = eval_math_expr(expr)
if res != result:
print("Computing", expr, "got", result, "instead of", res)

О negate

Вы установить negate ложь в самом начале и убедитесь, что вы сбросить его обратно в false на каждой итерации, так что на следующей итерации работает нормально. Было бы лучше инициализировать его в false в начале итерации. Вы также можете установить его, чтобы negate = expr[0] == '-'.

        negate = expr[0] == '-' #for negative numbers
if negate:
expr = expr[1:]
number1, end_number1 = get_number(expr)
expr = expr[end_number1:]
if negate:
number1 *= -1

Альтеративно могли бы справиться с этой частью get_number функция.

def get_number(varstr):
s = ""
if varstr[0] == '-':
s += "-"
varstr = varstr[1:]
for c in varstr:
if not is_digit(c):
break
s += c
return (int(s), len(s))

def eval_math_expr(expr):
while True:
try:
number1, end_number1 = get_number(expr)
expr = expr[end_number1:]
if expr == '':
return number1
op = expr[0]
expr = expr[1:]
number2, end_number2 = get_number(expr)
number1 = perform_operation(op, number1, number2)
expr = str(number1) + expr[end_number2:]
except Exception as e:
print(e)
break
return number1

Весь код:

import operator

DIGITS = set('0123456789')
OPERATIONS = {
'+' : operator.add,
'-' : operator.sub,
'*' : operator.mul,
'/' : operator.floordiv,
'^' : operator.pow,
}

def is_digit(var):
return var in DIGITS

def get_number(varstr):
s = ""
if varstr[0] == '-':
s += "-"
varstr = varstr[1:]
for c in varstr:
if not is_digit(c):
break
s += c
return (int(s), len(s))

def perform_operation(string, num1, num2):
op = OPERATIONS.get(string, None)
if op is not None:
return op(num1, num2)
else:
return None # How to handle this?

def eval_math_expr(expr):
while True:
try:
number1, end_number1 = get_number(expr)
expr = expr[end_number1:]
if expr == '':
return number1
op = expr[0]
expr = expr[1:]
number2, end_number2 = get_number(expr)
number1 = perform_operation(op, number1, number2)
expr = str(number1) + expr[end_number2:]
except Exception as e:
print(e)
break
return number1

if __name__ == '__main__':
interactive = False
if interactive:
expr = input('Enter your expression:')
print(expr + '=')
print(eval_math_expr(expr))
else:
for expr, res in {"2": 2, "2*4": 8, "4+8": 12, "100/3": 33, "2^3": 8, "-2": -2, "-2-3": -5}.items():
result = eval_math_expr(expr)
if res != result:
print("Computing", expr, "got", result, "instead of", res)

Реорганизация в основную функцию

На данный момент код разбирает два числа и операции, выполняет операцию, преобразовать результат в строку, которая будет проанализирована в следующей итерации. Таким образом, каждый временный результат преобразуется из integer в String то число. Это приводит к проблемам, когда результат не может быть преобразован назад и вперед, например при выполнении деления с нецелым результат. Также это может быть оптимизирован с следующей логике:


  • сделать первый номер и хранить его в качестве текущего числа

  • в каждой итерации: сделать операцию и на следующий число. Вычислительные операции и сохранить результат как текущее число, для повторного использования в следующей итерации.

  • в конце концов, возвращает номер текущей.

Вы могли бы написать это:

def eval_math_expr(expr):
n, end_n = get_number(expr)
expr = expr[end_n:]
while expr:
op, expr = expr[0], expr[1:]
n2, end_n = get_number(expr)
n = perform_operation(op, n, n2)
expr = expr[end_n:]
return n

6
ответ дан 18 февраля 2018 в 09:02 Источник Поделиться

ваш английский более чем хорошо ;)

Очень маленькие комментарии дать несколько советов на таком уровне:


  • Попробуйте немного лучше именования функций, является жизненно важным для тех, кто будет читать ваш код, чтобы помочь понять их. Представьте, что кто-то читать, например, первая функция Numbers(var) и попытаться выяснить, что он делает именно это имя. Я бы предложил именования, как is_digit(character) где легко понять, какие функции выполняет (проверяет, если что-то цифра), и какой параметр он ожидает (один символ)

  • Нудно сравнение одного символа, как var == '0' or... может быть лучше писать с помощью Python in оператора. Что о var in '0123456789'

  • Же именования можно использовать для def operator(operato):насчет is_operator(character)

  • Содержание в то время как статья немного Большой, вы можете рассмотреть разделив его на функции

Последнее, но не менее

#created by Estoria Wandertag, while he was sitting on the toilet and thought about life and programming

Это очень буквальный подход к сброс данных в интернете ;)

5
ответ дан 17 февраля 2018 в 08:02 Источник Поделиться

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

А. Ромеу отметил, что можно использовать в Python in оператора найти, если персонаж является одним из набора символов. Но есть и другие места, где Python включает языковые особенности, которые могут значительно упростить ваш код.

Например, взгляните на ваше operation() функция. Обратите внимание, что код повторяется, только оператор другой:


def operation(string, num1, num2):
if string == '+':
return num1 + num2
if string == '-':
return num1-num2
if string == '*':
return num1*num2
if string == '/':
return num1/num2
if string == '^':
return num1 ** num2

Обычный способ сделать что-то подобное в Python, чтобы предварительно построить dict сопоставление элементов для функций, выполняющих эти действия, затем вытащить функции из dict.

В данном случае, поскольку вы используете операторы, и они не могут быть сохранены в dictвам потребуется import operator для того чтобы получить функцию версии операторов. Затем ниже инструкцию import вы можете сказать

operations = {
'+' : operator.add,
'-' : operator.sub,
'*' : operator.mul,
'/' : operator.truediv}

def operation(operator, num1, num2):
return operations[operator](num1, num2)

Больше не дублировать код!

Что касается вашего основного кода, есть несколько вещей, чтобы улучшить, но я хочу сосредоточиться на дублирование кода. У вас есть строки, говоря:

    number1 = Test4Num(char)[0]
# ...
end_number1 = Test4Num(char)[1]

поэтому у вас есть два вызова Test4Num(char). Вместо этого, используйте несколько функций назначения в Python (также называется присваивание кортежа):

    (number1, end_number1) = Test4Num(char)

Это назначает как number и end_number1.

Также я думаю, что ваш окончательный print() ненужно; он выводит частичные промежуточные результаты просто бегут вместе; вы просто хотите, чтобы конечный результат, верно?

5
ответ дан 18 февраля 2018 в 03:02 Источник Поделиться