CLI Calculator in Python.

HarshHarsh
7 min read

Hello everyone!👋

I’m sure you’ve all seen many simple calculator tutorials online—whether on YouTube, other social media, or well you get the idea! There are tons of beginner-friendly calculator tutorials out there, but most are limited to something like this:

Enter n1 : 2
Enter n2 : 3
Enter operator (+,-,*,/) : +
Result : 5

As a coder and user, I found this approach a bit tedious. Entering numbers and operators separately feels clunky and restricts you from solving more complex expressions quickly. So, I thought, why not create a simple yet powerful calculator that can handle full mathematical expressions in one go? Something like this:

Enter : 23 - 21 * 32 / 34 + 1000
Result: 1003.2352941176471

I won’t say it’s perfect (don’t worry — the answer is correct!), but I really like how it lets me enter full expressions naturally. Plus, it’s a fun challenge to flex my problem-solving skills 😅. In this blog, I’ll share how I built this calculator, the hurdles I faced, and how you can create your own to tackle complex math with ease!

In this tutorial, I’ll keep things simple. There will still be room for improvement — and that part is up to you!
So, let’s get started! 🚀

The plan was quite simple.

  1. Take the user input, which would be an infix expression (something like this :- 2+1-2+32).

  2. Convert it into postfix. Which would look like this : [ 2,1,2,32,+,-,+ ].

  3. And then solve it. How? It’s explained later in this blog post.

1. Taking the user input.

def main():
    valid_inputs = ['0','1','2','3','4','5','6','7','8','9','+','-','*','/']
    try:
        user_input = input('Enter : ')
        user_input = user_input.replace(" ","")
        for char in user_input:
            if char not in valid_inputs:
                raise ValueError("Invalid input")
    except Exception as e:
        print(e)
        return
    userinput_to_infix_generator(user_input)
if __name__ == "__main__":
    main()

Inside the main() function I did two things.

  1. Taking the user input.

  2. Making sure that it was a valid input.

If there is problem with the expressions like having an invalid symbol the code immediately raises a value error.

valid_inputs = ['0','1','2','3','4','5','6','7','8','9','+','-','*','/']
    try:
        user_input = input('Enter : ')
        user_input = user_input.replace(" ","")
        for char in user_input: <-----
            if char not in valid_inputs:
                raise ValueError("Invalid input")
    except Exception as e:
        print(e)
        return

The loop checks each character (char) from the user's input. If any character isn't in the valid_inputs list, a ValueErroris raised. If all characters are valid, the code moves on to the next step.

Once it’s done with comparison and it was a success. It calls the function userinput_to_infix_generator(user_input) with user_input as argument.

The userinput_to_infix_generator(user_input) function takes the clean input and turns it into a list of tokens we can later convert from infix to postfix.

You're right! Here's your full section rewritten cleanly in Markdown, with everything from your original idea included, and polished for clarity and readability — all ready to be pasted into your blog:

userinput_to_infix_generator(user_input)

The code itself isn’t very complex — it just turns the user_input string into a list called infix, where each number and operator is stored as a separate item.

def userinput_to_infix_generator(user_input):
    infix = []
    temp = ""
    symbols = ['+', '-', '/', '*']
    for i in user_input:<-------
        if i not in symbols:
            temp = temp + i
        else:
            infix.append(temp)
            infix.append(i)
            temp = ""
    if temp:
        infix.append(temp)
    infix_to_postfix(infix)

The key part of this function is how it handles the input when numbers are written together without clear spaces — for example, 223+32. We don't want to treat '2', '2', and '3' as separate characters. Instead, we need to combine them into a full number like "223" and then store it in the list.

This is handled inside the loop:

  • If the character is not an operator (+, -, *, /), it's added to a temporary string temp.

  • When an operator is found, the function:

    1. Adds the number stored in temp to the infix list,

    2. Then adds the operator,

    3. And resets temp for the next number.

Finally, after the loop ends, if temp still holds the last number, it adds that to the list too.

Example:

For input: 12+7*5 The resulting infix list would be: ['12', '+', '7', '*', '5']

2. Convert it to postfix

Alright, now that we’ve turned our input string into a nice clean list (our infix expression), the next step is to convert that into postfix format. This part is super important — because computers find postfix (also known as Reverse Polish Notation) much easier to solve than regular infix math.

At first, I wrote a big if-else mess (you might’ve done that too 😅), but then I realized: why not use a simple approach that handles everything neatly using operator precedence?

Here’s the final version I settled on:

def infix_to_postfix(infix):
    postfix = []
    stack = []
    precedence = {'+': 1, '-': 1, '*': 2, '/': 2}
    for token in infix:
        if token not in precedence:
            postfix.append(token)
        else:
            while stack and precedence.get(stack[-1], 0) >= precedence[token]:
                postfix.append(stack.pop())
            stack.append(token)
    while stack:
        postfix.append(stack.pop())
    postfix_to_solution(postfix)

But what’s really going on here?

  • I created a precedence dictionary to decide which operators are stronger (* and / are stronger than + and -).

  • Then, I loop through each token in the infix list:

    • If it’s a number, it goes straight to the postfix list.

    • If it’s an operator, we compare it with the one on top of the stack:

      • If the stack's operator has higher or equal precedence, we pop it out and add it to postfix.

      • Otherwise, we just push our current operator onto the stack.

  • Once we're done looping, we pop any remaining operators from the stack and add them to the result.


Example Time!

Let’s say the infix expression is:

['12', '+', '7', '*', '5']

This function turns it into:

['12', '7', '5', '*', '+']

3. Solve it

postfix_to_solution(postfix)

Alright, we’ve got our expression nicely converted into postfix form. Now it’s time for the grand finale — solving it! This function takes that postfix list and actually computes the answer. Here's the code:

def postfix_to_solution(postfix):
    stack = []
    for token in postfix:
        if token.isdigit():
            stack.append(int(token))
        else:
            b = stack.pop()
            a = stack.pop()
            if token == '+':
                stack.append(a + b)
            elif token == '-':
                stack.append(a - b)
            elif token == '*':
                stack.append(a * b)
            elif token == '/':
                stack.append(a / b)
    if stack:
        print("Result:", stack[0])

What’s happening here?

This is a classic postfix evaluation using a stack:

  • If the token is a number, we push it onto the stack.

  • If it’s an operator (+, -, *, or /), we pop two numbers from the stack:

    • a and b, where a is the second-last and b is the last one pushed.
  • We perform the operation: a + b, a - b, etc., and push the result back onto the stack.

  • In the end, if everything went well, the stack will contain one final value — the answer!


Example:

Say your postfix list is:

['12', '7', '5', '*', '+']

Here's how the evaluation would go:

  1. Push 12

  2. Push 7

  3. Push 5

  4. See * → pop 5 and 7 → push 35

  5. See + → pop 35 and 12 → push 47

Final result: 47

Quick Note

This code uses int() to convert digits, so it won’t work with decimal numbers like 2.5 yet. If you want to support floats, just change int(token) to float(token) — easy fix!

And that’s it…, now ask yourself.
“Is there any room of improvement?”

Yes! A lot!.

There’s also one major issue with this calculator. Try giving it an input like 2++3-2 — yeah, it breaks! 😅 It doesn’t currently handle invalid operator sequences properly. I’m leaving this part on you to fix.

There are a lot of other things you can do with this, maybe try adding brackets support?.

🎯 Wrapping it up

This calculator may be simple, but building it helped me understand how real interpreters work behind the scenes. From reading input, validating it, converting between notations, and finally evaluating — it’s all there.

There’s still room for improvements — like handling decimals, parentheses, or even making a GUI. But I’ll leave that challenge to you!

Thanks for reading 😄
Let me know in the comments what you added or improved!

0
Subscribe to my newsletter

Read articles from Harsh directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Harsh
Harsh