7

I have 10 to 20 function with prefix name same, & I have to call them as per user input, But am not getting how to call them, I tried using below method but it's not working, Can anyone tell me how should I make function callable.

def pattern_1(no):
    print('First Pattern with ' +str(no)+ ' rows')

def pattern_2(no):
    print('Second Pattern with ' +str(no)+ ' rows')


rows = eval(input('Enter number of rows: '))
pattern_no = eval(input('Enter pattern num [1-10]: '))

cust_fun_name = 'pattern_' + str(pattern_no)

print(cust_fun_name) # Here its print pattern_2 but why function is not get invoked
cust_fun_name()

When I run above code am getting below error

Traceback (most recent call last):                                                                                
  File "/home/main.py", line 22, in <module>                                                                      
    cust_fun_name()                                                                                               
TypeError: 'str' object is not callable
redacted
  • 3,789
  • 6
  • 25
  • 38
Gajanan Kolpuke
  • 155
  • 1
  • 1
  • 14
  • **Do not ever use `eval` for data that could ever possibly come, in whole or in part, from outside the program. It is a critical security risk that allows the creator of that data to run arbitrary Python code in the current context. It cannot sanely be sandboxed.** – Karl Knechtel Oct 15 '22 at 05:54

3 Answers3

12

if the mapping is static, either make a mapping of function name to function object

mapping = {
  "pattern_1": pattern_1,
  "pattern_2": pattern_2
}

#do not use `eval` on user input!
pattern_no = input('Enter pattern num [1-10]: ')

cust_fun_name = 'pattern_' + str(pattern_no)
cust_func = mapping[cust_fun_name]
# call the function
cust_func()

or get the function object directly from the local namespace

cust_func = locals()['pattern_' + str(pattern_no)]
cust_func()
redacted
  • 3,789
  • 6
  • 25
  • 38
  • Eval is evil. No matter if it's Python, PHP or anything else. Have my upvote for telling OP – Manuel Mannhardt Sep 17 '18 at 06:22
  • So In that case whenever new function has been added then that function has to be add in mapping variable. And Thanks for the answer it resolves my problem. – Gajanan Kolpuke Sep 17 '18 at 06:43
  • 1
    @GajananKolpuke yes, if you use the first approach then you have to update the mapping. IF you decide to go with the alternative `locals()[...]`, then you don't need to do update anything, it will just work – redacted Sep 17 '18 at 07:36
  • @RobinNemeth how to add mypy annotation to cust_func in above scenario, because in normal case, annotations are added in `def` statement, i.e. def cust_func(a: str) -> int? – John Overiron Feb 14 '20 at 13:23
  • 2
    @JohnOveriron I think you could do `cust_func: Callable[[str], int] = mapping[cust_func_name]` – redacted Feb 15 '20 at 13:41
-1

If you really want to do it this way, you can use eval():

def pattern_1(no):
    print('First Pattern with ' +str(no)+ ' rows')

def pattern_2(no):
    print('Second Pattern with ' +str(no)+ ' rows')

rows = input('Enter number of rows: ')
pattern_no = input('Enter pattern num [1-10]: ')

cust_fun_name = 'pattern_' + pattern_no
print(cust_fun_name) 
eval(cust_fun_name+"("+rows+")") # This is how you use eval()

# Enter number of rows: >? 10
# Enter pattern num [1-10]: >? 1
# pattern_1
# First Pattern with 10 rows

However, I think you should follow Robin's answer, that's the legit way to use Python.

Kevin Fang
  • 1,966
  • 2
  • 16
  • 31
  • **Do not ever use `eval` for data that could ever possibly come, in whole or in part, from outside the program. It is a critical security risk that allows the creator of that data to run arbitrary Python code in the current context. It cannot sanely be sandboxed.** – Karl Knechtel Oct 15 '22 at 05:54
-1
def pattern_1(no):
    print('First Pattern with ' +str(no)+ ' rows')

def pattern_2(no):
    print('Second Pattern with ' +str(no)+ ' rows')


rows = eval(input('Enter number of rows: '))
pattern_no = eval(input('Enter pattern num [1-10]: '))

pattern_2(no)
cust_fun_name = 'pattern_' + str(pattern_no)

print(cust_fun_name) # Here its print pattern_2 but why function is not get invoked

eval(cust_fun_name)()
Kevin Fang
  • 1,966
  • 2
  • 16
  • 31
yanjie lu
  • 1
  • 1
  • 2
    Please edit your answer, as it lacks explanation, and the line `pattern_2(no)` comes out of nowhere. And the final line can't execute properly. – Kevin Fang Sep 17 '18 at 06:21
  • **Do not ever use `eval` for data that could ever possibly come, in whole or in part, from outside the program. It is a critical security risk that allows the creator of that data to run arbitrary Python code in the current context. It cannot sanely be sandboxed.** – Karl Knechtel Oct 15 '22 at 05:53