0

I am new to python. I have been coding a python calculator but floats are annoying because 0.1 + 0.2 != 0.3 so I have been using the decimal module. I have coded a script to convert the floats from the input to a decimal. I have first formatted the input string and then splitted it into a list. I run my script (for loop) on this list (called evalvar) but whenever I change the value of the i (iteration) to overwrite evalvar, nothing happens. Code:

evalvar = ["0.1", "+0.2"]
for i in evalvar:
    try:
        #i is now equal to "0.1"
        i = str("""Decimal('""" + i + """')""")
        #i is now equal to """Decimal('0.1')"""
    except SyntaxError:
        print(evalvar)

I have worked out the answer myself. Instead of using for i in evalvar I have used for i in range(len(evalvar)) and replaced all the i's in my for loop with evalvar[i].

Gig A Byte
  • 31
  • 4
  • You may use session – Ikram Ud Daula Oct 10 '17 at 07:10
  • 1
    Sorry, what do you mean by session? – Gig A Byte Oct 10 '17 at 07:11
  • Strings are immutable, you *can’t* change i in a way that’s reflected in evalvar. You could replace it by index instead. But note that creating the string isn’t actually creating a Decimal; if you’re planning to then `eval` that I’d strongly recommend you reconsider. – jonrsharpe Oct 10 '17 at 07:14
  • @IkramHasib what *do* you mean? – jonrsharpe Oct 10 '17 at 07:14
  • @jonrsharpe so I cannot permanently change the value of i from inside the for loop, how do i use the index? – Gig A Byte Oct 10 '17 at 07:15
  • This is not really a Pythonic code. You might go through some nice tutorials, just to get the basics of it. For example http://www.diveintopython.net/ or https://docs.python.org/3.6/tutorial/floatingpoint.html – marw Oct 10 '17 at 07:19
  • @jonrsharpe dont worry worked it out :) – Gig A Byte Oct 10 '17 at 07:20
  • just to be sure: will you then use `eval(evalvar)` to execute the string you just generated ? Because if you want to do that, then there are a lot of better, cleaner, faster and safer ways to do the same thing. `eval` is to be avoided at all costs in Python – Guillaume Oct 10 '17 at 07:23
  • @Guillaume, I know what I'm doing with my eval(). The program I have coded requires eval() in many places but I have made sure that the content of eval() cannot contain user specific input. – Gig A Byte Mar 07 '18 at 06:51

1 Answers1

0

Rebinding the iteration variable (i) will of course not modify your evalvar list, and since strings are immutable you can not update it in place either. The solutions here are either to build a new list:

# use string formatting instead of concatenation (more readable)
# and use a list expression (idiomatic and more efficient)
evalvar = ["Decimal('{}')".format(value) for value in evalvar]

or to update the list in place using indices:

# `enumerate(sequence)` yields an `index, value` tuple
# for each item in `sequence`
for index, value in enumerate(evalvar):
    evalvar[index] =  "Decimal('{}')".format(value)

This being said, building code as strings and passing it to eval or ast.literal_eval (which I assume is your plan) is certainly not the best solution. You'd be better parsing your input to an operand, operator, operand triplet, build numericals from the operand and use the operator module for operations ie:

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

def parse_exp(inp):
    parsed = [item.strip() for item in inp.split(" ")]
    operator = parsed.pop(1)
    operands = [Decimal(item) for item in parsed]
    return operator, operands

def eval_exp(inp): 
    operator, operands = parse_exp(inp)
    return operations[operator](*operands)

def main():
    inp = "0.1 + 0.2"
    print(eval_exp(inp))
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118