0

I'm trying to make a program to calculate compound interest to figure out keyword arguments for functions, by accepting inputs for the principal, time, and rate, in Python.

After checking if the entered values are not blank and are numeric, I use eval to use them as Named Arguments for the function, but I get SyntaxError: invalid syntax.

Could I get help with where I'm going wrong?

The code:

def compound(principal = 10000, time = 20, rate = 4):
  amt = principal * (((rate/100) + 1) ** time)
  return amt

p = input("Enter principal amount: ")
r = input("Enter the rate of interest per annum: ")
t = input("Enter the time period(in years): ")

arg = []

if p != "" and p.isnumeric():
  arg += ["principal = " + p]
if r != "" and r.isnumeric():
  arg += ["rate = " + r]
if t != "" and t.isnumeric():
  arg += ["time = " + t]

print(compound(eval(", ".join(arg))))

Output:

Enter principal amount: 1000
Enter the rate of interest per annum: 4.5
Enter the time period(in years): 10
Traceback (most recent call last):
  File "main.py", line 18, in <module>
    print(compound(eval(", ".join(arg))))
  File "<string>", line 1
    principal = 1000, time = 10
              ^
SyntaxError: invalid syntax
Vaurkhorov
  • 13
  • 3
  • Related: https://stackoverflow.com/questions/8818318/how-to-eval-a-string-containing-an-equal-symbol – David Brabant Apr 04 '21 at 06:49
  • 1
    Besides this: Why are you forcing yourself to use eval()? There are more pythonic ways to handle the issue, i.e. parsing the arguments into the function "normally". Any explicit reason to use eval()? – J. M. Arnold Apr 04 '21 at 06:51
  • I used eval() so that I can omit any argument that's blank or invalid. Is there another way? – Vaurkhorov Apr 04 '21 at 06:54
  • 1
    Build a dict and use `**`. – user2357112 Apr 04 '21 at 06:55
  • @Vaurkhorov Yes, by using "default arguments" (you already did this). That means that e.g. principal, whether you parse it to the function or not, has already a value, in this case 10000. – J. M. Arnold Apr 04 '21 at 06:56
  • 1
    @J.M.Arnold: That's not what "positional arguments" means. – user2357112 Apr 04 '21 at 06:56
  • @user2357112supportsMonica Thanks - I just noticed it while re-reading my reply. – J. M. Arnold Apr 04 '21 at 06:58
  • If the value stored in the dictionary for, say, `p` in this example is a blank string, will it skip that when I use `**`? – Vaurkhorov Apr 04 '21 at 06:59
  • I did use default arguments, but I can't figure out how to call the function... If I use something like `compound(p,r,t)` but p is a blank string, won't that cause an error? – Vaurkhorov Apr 04 '21 at 07:02

2 Answers2

1

You can build a dict containing your arguments, and unpack it when calling the function.

In order to avoid code repetition, you can create a list of the target arguments with the corresponding input message.

If the user enters an empty string, we just ignore this input, and don't add any entry for this parameter to our dict. This way, the default argument will be used when we call the function.

def compound(principal = 10000, time = 20, rate = 4):
    amt = principal * (((rate/100) + 1) ** time)
    return amt

inputs = [('principal', "Enter principal amount: "),
          ('rate', "Enter the rate of interest per annum: "),
          ('time', "Enter the time period(in years): ")]

data = {}
for target, message in inputs:
    inp = input(message)
    if inp:
          data[target] = float(inp)

print(compound(**data))

Sample run:

Enter principal amount: 
Enter the rate of interest per annum: 10
Enter the time period(in years): 1
11000.0

In this case, when we called the function, data was {'rate': 10.0, 'time': 1.0}

Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
  • From what I understand from this, in `if inp:` inp will return False if blank, and will skip. Is that correct? – Vaurkhorov Apr 04 '21 at 07:16
  • That's right. Empty strings, lists, tuples, dicts... all evaluate as `False` in boolean context. – Thierry Lathuille Apr 04 '21 at 07:16
  • Understood, but will it work for, say `("")`, where the tuple has an empty string? – Vaurkhorov Apr 04 '21 at 07:21
  • `("")` is not a tuple, it's just `""` - The commas make the tuple, not the parentheses. But the tuple containing an empty string (which is written `("", )`) is not empty, so it will be considered `True`. – Thierry Lathuille Apr 04 '21 at 07:24
0

There are few errors in your code

  1. isnumeric - is applied to str object p=str(p) converting input to str.
  2. str should be unicoded depending on your python version for checking to isnumeric. unicode(p, 'utf-8').isnumeric()
  3. Arguments are passed separately to the function compound(int(p), int(r), int(t)) not as a single string.

your method compound excepts 3 arguments and you are passing a single string in which values are comma-separated. if you want to do that then your method should accept a single string. and you need to split your input based on spaerator ',' and assign value to variables accordingly.

  amt = principal * (((rate/100) + 1) ** time)
  return amt

p = input("Enter principal amount: ")
r = input("Enter the rate of interest per annum: ")
t = input("Enter the time period(in years): ")

arg = []
p=str(p)
r=str(r)
t=str(t)

if p != "" and  unicode(p, 'utf-8').isnumeric():
  arg += ["principal = " + p]
if r != "" and unicode(r, 'utf-8').isnumeric():
  arg += ["rate = " + r]
if t != "" and unicode(t, 'utf-8').isnumeric():
  arg += ["time = " + t]

print(compound(int(p), int(r), int(t)));
ankursingh1000
  • 1,349
  • 1
  • 15
  • 21