• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Python jak ulepszyć kalkulator?

Object Storage Arubacloud
+2 głosów
726 wizyt
pytanie zadane 21 kwietnia 2022 w Python przez niezalogowany

Zrobiłem kalkulator w Pythonie i już od dłuższego czasu myślę i nie wiem jak go ulepszyć w taki sposób aby wykonywał działania na więcej niż 2 liczbach.

np. 2*2*2+4-7

import os
def calculator(number_1,character_action,number_2):
            if character_action == '+':
                result = number_1+number_2
                print(number_1,' ',character_action,' ',number_2,' ','=',' ',result)
                
            elif character_action == '-':
                result = number_1-number_2
                print(number_1,' ',character_action,' ',number_2,' ','=',' ',result)
                
            elif character_action == '/':
                result = number_1/number_2
                print(number_1,':',number_2,' ','=',' ',result)
                
            elif character_action == '*':
                result = number_1*number_2
                print(number_1,' ',character_action,' ',number_2,' ','=',' ',result)
                
            else:
               print("Wprowadź znak działania bez spacji a nie: ",character_action)
            return


while True:        
     try:

         number1 = input("Wprowadź cyfrę")
         os.system("cls")
         number_1 = int(number1)
         character_action = input("Wprowadź znak działania:'+','-','/','*'")
         os.system("cls")
         number2 = input("Wprowadź kolejną cyfrę")
         number_2 = int(number2)
     
         
     except:
         print('Error')
     calculator(number_1,character_action,number_2)
     question = input("Chcesz dalej używać kalkulatora? napisz Tak lub Nie")
     questions = question.lower()
    
     if questions == 'tak':

            os.system("cls")

     elif questions == 'nie':

         os.system("cls")
         print("Okej")
         break
              
     else:
           os.system("cls")
           break
    

 

komentarz 21 kwietnia 2022 przez VBService Ekspert (252,740 p.)
edycja 21 kwietnia 2022 przez VBService

BTW, proponuję zapisać def calculator np. tak

[ UPDATE ]

def calculator(number_1,character_action,number_2):
    character_action = character_action.strip()
    if character_action in ['+', '-', '/', '*']:
        if character_action == '+': result = number_1+number_2
        if character_action == '-': result = number_1-number_2
        if character_action == '/': result = number_1/number_2
        if character_action == '*': result = number_1*number_2
        
        print(number_1,' ',character_action,' ',number_2,' = ',result)
    else:
        print("Wprowadź poprawny znak działania.\nWprowadzony znak: ", character_action)

lub wersja python 3.10+

def calculator(number_1,character_action,number_2):
    match character_action.strip():
        case '+': result = number_1+number_2
        case '+': result = number_1+number_2
        case '/': result = number_1/number_2
        case '*': result = number_1*number_2
        case _: 
            print("Wprowadź poprawny znak działania.\nWprowadzony znak: ", character_action)
            return
    
    print(number_1,' ',character_action,' ',number_2,' = ',result)

 

 

podobnie tutaj

    question = input("Chcesz dalej używać kalkulatora? napisz (T)ak lub (N)ie: ")
    questions = question.lower()
     
    if questions in ['tak', 't']:
        os.system("cls")
    elif questions in ['nie', 'n']:
        os.system("cls")
        print("Okej")
        break
    else:
        os.system("cls")
        break

 

zamiast 

os.system("cls")

proponuję bardziej uniwersalną wersję (pod: Windows, Linux i chyba iOS?)

clearScreen = lambda: os.system('cls' if os.name in ('nt', 'dos') else 'clear')

czyli

import os

clearScreen = lambda: os.system('cls' if os.name in ('nt', 'dos') else 'clear')

def calculator(number_1,character_action,number_2):
    character_action = character_action.strip()
    if character_action in ['+', '-', '/', '*']:
        if character_action == '+': result = number_1+number_2
        if character_action == '-': result = number_1-number_2
        if character_action == '/': result = number_1/number_2
        if character_action == '*': result = number_1*number_2

        print(number_1,' ',character_action,' ',number_2,' = ',result)
    else:
        print("Wprowadź poprawny znak działania.\nWprowadzony znak: ", character_action)
 
while True:        
    try:
        number1 = int(input("Wprowadź cyfrę: "))
        clearScreen()
        number_1 = int(number1)
        character_action = input("Wprowadź znak działania '+','-','/','*': ")
        clearScreen()
        number2 = input("Wprowadź kolejną cyfrę: ")
        number_2 = int(number2)

        calculator(number_1, character_action, number_2)
    except:
        print('Error')         

    question = input("Chcesz dalej używać kalkulatora? napisz (T)ak lub (N)ie ")
    questions = question.lower()
     
    if questions in ['tak', 't']:
        clearScreen()
    elif questions in ['nie', 'n']:
        clearScreen()
        print("Okej")
        break
    else:
        clearScreen()
        break

 

komentarz 21 kwietnia 2022 przez manjaro Nałogowiec (37,390 p.)

Nie działa coś ten kalkulator wysypuje mi się

sh: linia 1: cls: nie znaleziono polecenia

 

komentarz 21 kwietnia 2022 przez Eryk Andrzejewski Mędrzec (164,260 p.)

@VBService, nie za dużo tego stripowania? wink

Osobiście w ogóle wyrzuciłbym je z tej funkcji i zrobił przy korzystaniu z inputa.

1
komentarz 21 kwietnia 2022 przez VBService Ekspert (252,740 p.)

Zostawiłem w if przez przypadek. Już poprawione.  laugh

2 odpowiedzi

+1 głos
odpowiedź 21 kwietnia 2022 przez Eryk Andrzejewski Mędrzec (164,260 p.)

To ciekawy problem, ale nie jest taki prosty. Od biedy mógłbyś użyć funkcji eval(), która parsuje i wykonuje pythonowe wyrażenie, z tym że dałbyś zbyt duże pole do popisu użytkownikowi, szczególnie temu złośliwemu (mógłby wykonać prawie dowolną operację, poprzez przekazanie odpowiednieg kodu).

Więc pozostaje inne rozwiązanie. Możesz zrobić własny parser wyrażeń, uwzględniając cechy operatorów (priorytet, łączność), a następnie zapisać takie wyrażenie w postaci drzewa składniowego (szukaj w wyszukiwarce pod frazą: math AST). Potem poruszając się po takim drzewie można obliczyć wartość wyrażenia. Ale wydaje mi się, że na początek prostsze będzie inne wyjście. Poczytaj sobie o ONP (Odwrotnej Notacji Polskiej; po angielsku RPN).

ONP to notacja, która pozwala zapisać każde wyrażenie, ale bez konieczności używania nawiasów. Nawiasy są potrzebne w notacji infiksowej, czyli takiej jaką posługujemy się na co dzień (infiksowa, bo operator wstawiamy pomiędzy argumenty). Natomiast ONP to notacja postfiksowa, na początku podajemy argumenty, a dopiero na końcu operator.

Przykładowe wyrażenie w postaci infiksowej: 5 * 4 + 9 * (2 - 1)

To samo wyrażenie w ONP: 5 4 * 9 2 1 - * +

Mniej więcej działa to tak, że napotykając na operand (czyli liczbę) wrzucamy ją na wierzch stosu, natomiast kiedy napotkamy na operator, pobieramy z góry stosu, w odpowiedniej kolejności, tyle liczb, ile operator przyjmuje argumentów (czyli w naszym przypadku dwa). Następnie wylicza się wynik takiej operacji (jest to dokładnie to, co ty teraz masz w swoim kodzie), a następnie wrzuca sie ten wynik na górę stosu. Jeśli wiesz jak działa stos to super, a jeśli nie - zapoznaj się z tym.

Można powiedzieć, że wyrażenia w postaci ONP przetwarza się dokładnie tak samo, jak gdyby ktoś kazał nam policzyć wartość wyrażenia w głowie lub na kartce. Widząc podane przeze mnie przykładowe wyrażenie mogę powiedzieć, że najpierw pomnożył bym 5 * 4, później odjąłbym 2 - 1, następnie pomnożył wynik odejmowania przez 9 i dodał dwie liczby w które w ten sposób uzyskam. Kwestia ładnego zapisania tego, aby operandy dla danych operatorów się zgadzały.

Jak już zrobisz program do ewaluacji wyrażenia zapisanego w ONP możesz spróbować zaimplementować algorytm, który konwertuje wyrażenie z postaci infiksowej, na postfiksową. Przykładowy algorytm jest omówiony na Wikipedii.

Jako ciekawostkę mogę powiedzieć, że stare kalkulatory HP (np. HP-48) korzystały właśnie z ONP do wykonywania obliczeń. smiley

2
komentarz 30 kwietnia 2022 przez Oscar Nałogowiec (29,290 p.)
Kalkulatory z ONP można poznać po tym, że miały klawisz oznaczony ENTER a nie miały =. Klawisz ENTER służył do wprowadzania na stos.
0 głosów
odpowiedź 29 kwietnia 2022 przez VBService Ekspert (252,740 p.)
edycja 30 kwietnia 2022 przez VBService

Nie przekreślałbym tak szybko eval() bo można się pokusić o sprawdzenie danych pochodzących od użytkownika przed poddaniem ich ewaluacji (evaluation).

 

przykład (dozwolone znaki - all())  [ on-line ]

import os, re

def clearConsole():
    os.system('cls' if os.name in ('nt', 'dos') else 'clear') 

def comma2Dot(value):
    return value.replace(",", ".")
    
def removeSpaces(value):
    return re.sub(r"\s", "", value)

def insertValueFor(expression, variable, value):
    return expression.replace(variable, value)
    
allowedCharacters = [ 
                      ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                      '+', '-', '*', '/', '(', ')', '.', 'p', 'i', 'x', 'r'
                    ]
    
while True:
    expression = input("Wprowadź wyrażenie: ")
    expression = removeSpaces(expression.lower())
    if expression == "": continue

    expression = comma2Dot(expression)

    if all(character in allowedCharacters for character in expression):
        if "x" in expression:
            x = float(comma2Dot(input("Podaj wartość dla x: ")))
            expression = insertValueFor(expression, "x", str(x)) 
        if "r" in expression:
            r = float(comma2Dot(input("Podaj wartość dla r: ")))
            expression = insertValueFor(expression, "r", str(r)) 
        if "pi" in expression:
            expression = insertValueFor(expression, "pi", "3.14") 

        try:
            print("\n" + expression)
            print(round(eval(expression), 2))
        except ZeroDivisionError:
            print("Bład dzielenia przez zero")
        except:
            print("Nieprawidłowe wyrażenie")        
    else:
        if expression in ["s", "stop"]:
            exit()
        elif expression in ["c", "cls"]:
            clearConsole()
            continue
        else:
            print("Wprowadzone wyrażenie zawiera niedozwolone znaki")
            
    print()

 

przykład (dozwolone znaki - regular expression)  [ on-line ]

import os, re

def clearConsole():
    os.system('cls' if os.name in ('nt', 'dos') else 'clear') 

def comma2Dot(value):
    return value.replace(",", ".")
    
def removeSpaces(value):
    return re.sub(r"\s", "", value)

def insertValueFor(expression, variable, value):
    return expression.replace(variable, value)

    
while True:
    expression = input("Wprowadź wyrażenie: ")
    expression = removeSpaces(expression.lower())
    if expression == "": continue

    expression = comma2Dot(expression)

    if re.match("^[0-9pirx+-/*().]*$", expression):
        if "x" in expression:
            x = float(comma2Dot(input("Podaj wartość dla x: ")))
            expression = insertValueFor(expression, "x", str(x)) 
        if "r" in expression:
            r = float(comma2Dot(input("Podaj wartość dla r: ")))
            expression = insertValueFor(expression, "r", str(r)) 
        if "pi" in expression:
            expression = insertValueFor(expression, "pi", "3.14") 

        try:
            print("\n" + expression)
            print(round(eval(expression), 2))
        except ZeroDivisionError:
            print("Bład dzielenia przez zero")
        except:
            print("Nieprawidłowe wyrażenie")        
    else:
        if expression in ["s", "stop"]:
            exit()
        elif expression in ["c", "cls"]:
            clearConsole()
            continue
        else:
            print("Wprowadzone wyrażenie zawiera niedozwolone znaki")
            
    print()

 

 

można też:

Example of the solving exploitation with the eval()

 

We can solve this security problem by using safe dictionaries. We can create a safe dictionary containing holding only the x as its value corresponding to the key ‘x’. This dictionary is given as the second parameter of the eval() so that only x will be identified as a global variable while evaluating.

This will prevent the eval() function from accessing the get_pass() function as it does not have this as a global variable to call. And this makes the password or any other confidential data secure.

This example is shown in the below code.

 

def get_pass():
    password='python@123'
    return password

exp=input('Enter an expression: ')
x=int(input("Enter the value of x: "))

safe_dic={}
safe_dic['x']=x
eval(exp,safe_dic)

Podobne pytania

0 głosów
1 odpowiedź 17,296 wizyt
pytanie zadane 26 października 2017 w JavaScript przez olekjs Gaduła (4,540 p.)
0 głosów
1 odpowiedź 1,638 wizyt
pytanie zadane 12 lipca 2020 w Python przez LogicznaLogika Nowicjusz (200 p.)
0 głosów
1 odpowiedź 1,296 wizyt
pytanie zadane 25 maja 2020 w Python przez hellobm Nowicjusz (170 p.)

92,551 zapytań

141,399 odpowiedzi

319,531 komentarzy

61,938 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...