HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Basic math interpreter

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
interpretermathbasic

Problem

Essentially what I've done here is written an Interpreter that takes in Python math, such as this, 23 ** 374748, and prints out the result. This program relies on the fact that in Python 2.7 input() is "broken". This means it can take in Python math.

# Main parser class
class Parser(object):
    def __init__(self):
        self.PROMPT = "MaTh @ ==> "
        self.ERR_MSG = "Error: Invalid math!"

    # Parse inputted math
    def parse_math(self):
        while True:
            try:
                math = input(self.PROMPT)
                print "{}\n".format(math)
            except:
                print self.ERR_MSG

# Run the program
if __name__ == "__main__":
    Parser().parse_math()


Can I improve anything here? Is it possible for this to be Python3 compatible?

Solution

For 2.x and 3.x compatibility, I would explicitly use eval(raw_input(...)); you can then use:

import sys

if sys.version_info[0] > 2:
    raw_input = input


This makes more sense if you're writing for 2.x first, and is slightly easier than shoehorning eval onto 3.x's input everywhere you need it (which also makes life more difficult everywhere you don't).

Also for compatibility, print is a function in 3.x. You can import from __future__, or just use

print("{}\n".format(math))


in both.

You could make the constants class attributes:

class Parser(object):

    PROMPT = "..."
    ERR_MSG = "..."

    def parse_math(self):
        ...


These are still accessible via self, so your other code doesn't change. Note that now there are no instance attributes, you don't need __init__. In fact, you could take this further and make parse_math a class method, then you don't need to create an instance to call it.

Try giving the user a way to escape the loop. Perhaps:

while True:
    math = raw_input(self.PROMPT)
    if math.lower() == "done":
        break
    try:
        math = eval(math)
    except (NameError, SyntaxError):
        print(self.ERR_MSG)
    else:
        print("{}\n".format(math))


Note here also

  • Splitting input and evaluation to allow pre-evaluation checking;



  • Catching specific errors (see e.g. here); and



  • Using the else to minimise the code in the try block.



Finally, your code has no documentation. This is simple enough to not really need it, but it's a habit worth getting into. See e.g. PEP-257.

Code Snippets

import sys

if sys.version_info[0] > 2:
    raw_input = input
print("{}\n".format(math))
class Parser(object):

    PROMPT = "..."
    ERR_MSG = "..."

    def parse_math(self):
        ...
while True:
    math = raw_input(self.PROMPT)
    if math.lower() == "done":
        break
    try:
        math = eval(math)
    except (NameError, SyntaxError):
        print(self.ERR_MSG)
    else:
        print("{}\n".format(math))

Context

StackExchange Code Review Q#59646, answer score: 3

Revisions (0)

No revisions yet.