Byte wrote: >> parse the expression, extract the operands and the operation, apply the > operation to the operands > > How? Give me some example code, but please keep it simple. > >> are you trying to code a calculator? > > Not intending to, just trying to learn Python. Suppose what i'm trying > to code is a but like a CLI calculator, but i'm just writing it for my > own educational beifits. >
Side note: have you read Dive into Python (http://diveintopython.org/) yet? If you haven't -- and are done reading the whole python tutorial -- you should, it's a very good and practical read. Now about the calculator, let's do a simple RPN notation (they're much simpler to compute than the "regular" notation, see http://en.wikipedia.org/wiki/RPN for some informations about RPN) First, we need an input --> expression = raw_input("> ") <-- Now we need to handle this input. An RPN expression is a space-separated list of tokens, these tokens being either operands (numbers) or operations. This means that we merely need to split our expression at the spaces --> expression = raw_input("> ") tokens = expression.split() # split a string using spaces as default split delimiter <-- Now we have a list of tokens. RPN calculations involve a stack, to keep the current operands. Python's `list` has everything you need to emulate a stack --> expression = raw_input("> ") tokens = expression.split() # split a string using spaces as default split delimiter stack = list() <-- Now, we have to handle each token. Either a token is a number (an operand), in which case we have to convert it to an integer (it's currently stored as a string), or it's an operation, in which case we have to apply the operation on the last two tokens of the computation stack and store the result back on the stack. This means that we have to store addition, substraction, multiplication and division. Luckily, there is the python module `operator` that stores an accessor to these operations (add, sub, mul, div). We could store them in a dictionary with an operation token as index: we feed the operation token to the dict, it outputs the operation function. --> import operator operations = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.div } expression = raw_input("> ") tokens = expression.split() # split a string using spaces as default split delimiter stack = list() <-- Good, now all we need to know is to feed each token to the `operations` dict, let's try with the first token of the RPN expression "1 2 + 4 * 3 +" >>> operations['1'] Traceback (most recent call last): File "<pyshell#12>", line 1, in -toplevel- operations['1'] KeyError: '1' Well, there is no "1" key in our dictionary, so we get an error. Kind of obvious. The Python dictionaries also have a "get" method that takes a key and a value, and they return the value (default) if the key doesn't exist, how would that one fare? >>> operations.get('1',None) >>> operations.get('2',None) >>> operations.get('+',None) <built-in function add> >>> Ok, it's return the operation function if it knows the token we feed it, and "None" if it doesn't. Now all we have to do is check if it returns None, and if it does we know it's an operand and not an operation. First we need to loop on the list of tokens: --> import operator operations = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.div } expression = raw_input("> ") tokens = expression.split() # split a string using spaces as default split delimiter stack = list() for token in tokens: operation = operations.get(token, None) if operation: # If operation is not "None", therefore if the token was an operation token pass # do nothing for now else: # if operation is "None" == if the token is an operand token pass # do nothing either <-- Ok, what are we supposed to do if the token is an operand? Convert the operand (token) to an integer (the token is a string), and then add it to our computational stack. The last part is done via the `append` methods of Python's list. If the token is an operation, we have to apply the operation to the last two operands of the stack, and push the result back on the stack To get the last operation of a Python list, we use the `pop`method, it defaults to returning the last value of a list. --> import operator operations = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.div } expression = raw_input("> ") tokens = expression.split() # split a string using spaces as default split delimiter stack = list() for token in tokens: operation = operations.get(token, None) if operation: # If operation is not "None", therefore if the token was an operation token result = operation(stack.pop(), stack.pop()) # apply the operation on the last two items of the stack stack.append(result) # put the result back on the stack else: # if operation is "None" == if the token is an operand token stack.append(int(token)) # Convert the token to an integer and push it on the stack <-- Ok, let's test that shall we? What happens if we feed it "1 2 + 4 * 3 +", this should return 15 = (1+2)*4+3. The result is the only item that should be left on our stack --> >>> operations = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.div } >>> expression = raw_input("> ") > 1 2 + 4 * 3 + >>> tokens = expression.split() # split a string using spaces as default split delimiter >>> stack = list() >>> for token in tokens: operation = operations.get(token, None) if operation: # If operation is not "None", therefore if the token was an operation token result = operation(stack.pop(), stack.pop()) # apply the operation on the last two items of the stack stack.append(result) # put the result back on the stack else: # if operation is "None" == if the token is an operand token stack.append(int(token)) # Convert the token to an integer and push it on the stack >>> stack [15] >>> <-- Gread. Now let's try it again with the expression "1 4 -". This should return -3. --> >>> # snip >>> stack [3] <-- Duh, the result is wrong. This is because when we do operation(stack.pop(), stack.pop()), we use the last value of the stack as the first operand of our operation (here, our expression resolves to "operator.sub(4, 1)" which is equivalent to "4-1", which is wrong). Let's get out operands in the good order by replacing that line with --> operand2 = stack.pop() operand1 = stack.pop() result = operation(operand1, operand2) <-- And now it works, we have a basic RPN calculator. Homework: truth is that this calculator kind of sucks: it's very easy to break it. Try using "-" as your input expression. Or "1 +", or "1 56 + +". What happens? Try to modify the calculator to avoid these errors, or handle them gracefully. Likewise, entering the expression "5 0 /" results in a Division By Zero error. Try to handle it to display a friendly message instead of having the calculator blow. You have to rewrite everything every time you want to compute a new expression. Modify the calculator to always ask for new expression until a specific command is entered (such as "exit") The calculator breaks (again) if you use a token that is neither an integer nor an operation (e.g. "1 foo +", or even "foo") Modify it to handle that kind of false input without exploding in your hands. The output is ugly (a list of only one item), try to improve it. Computing the expression "5 3 /" (5/3) returns "1". Why? How can you improve it? Additionally, you currently cannot use floating point numbers (e.g. "1.5 1.3 +") in your expressions (guess what the calculator does?), see if you could modify the calculator to handle floating point numbers. Last, but not the least, try to create a Polish Notation calculator (prefix notation, it's like RPN but the operation is in front of the operand) and a "maths notation" calculator. -- http://mail.python.org/mailman/listinfo/python-list