-1

I've been trying to store and then call a string and/or a function inside a dictionary.

First example

def mainfunction():
    dict = {
        'x' : secondfunc,
        'y' : 'hello world'
    }
    while True :
        inpt = input('@')
        dict[inpt]()
    
def secondfunc():
    print('hi world')

mainfunction()

This works only if I input the key 'x'. If I try to input key 'y', I get this error.

TypeError: 'str' object is not callable

Also, the problem with this method is that it can't make a default answer.

Second example

def mainfunction():
    dict = {
        'x' : secondfunc,
        'y' : 'hello world'
    }
    while True:
        inpt = input('@')
        z = dict.get(inpt, 'Default text')
        print(z)
        
def secondfunc():
    print('hi world')
    
mainfunction()

This method works for key 'y', but for key 'x' it prints something to the effect of:

<function secondfunc at 0x7ab4496dc0>

I'm trying to make it so that whichever value I input, it will either print a default value, print a string, or execute a function. All depending on the key input.

Last example

The only solution I've found is that which uses if statements.

def mainfunction():
    dict = {
        'x' : secondfunc,
    }
    dict2 = {
        'y' : 'hello world'
    }
    
    while True:
        inpt = input('@')
        z = dict2.get(inpt, 'Default text')
        if inpt == 'x':
            dict[inpt]()
        else:
            print(z)
        
def secondfunc():
    print('hi world')
    
mainfunction()

This solution takes more code than I would like it to, and it also requires an if statement specific to the dictionary given, which takes more time. Is there no better way to do this?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • It's exactly as the error says: strings are not a kind of thing that you call. Can you think of something that you *can* call (hint: maybe the other kind of thing currently being stored?) that could give you the desired string when it is called (hint: maybe by `return`ing it)? – Karl Knechtel Aug 17 '22 at 04:46

4 Answers4

1

Instead of a string itself, you need to store a function returning a string in the dictionary.

Most simply this can be done as an anonymous function using the lambda syntax:

answers = {
    'x': secondfunc,
    'y': lambda: 'hello world'
}

(It's bad practice to name this dictionary dict, because it shadows the built-in dict, so I'll use a better name here.)

Of course, secondfunc should not print a string, but return a string, as well, since printing is already the job of mainfunc (see also: Difference between returns and printing in python?):

def secondfunc():
    return 'hi world'

Now, print(answers['x']()) and print(answers['y']()) are working equally.

To create a default answer with the dictionary .get() method, it also needs to be a function returning a string:

def mainfunction():
    answers = {
        'x' : secondfunc,
        'y' : lambda: 'hello world'
    }
    while True:
        inpt = input('@')
        z = answers.get(inpt, lambda: 'Default text')()
        print(z)
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
0

You can use the callable() function to test if the dictionary value is a function. If it is, call it, otherwise just print the value itself.

def mainfunction():
    dict = {
        'x' : secondfunc,
        'y' : 'hello world'
    }
    while True:
        inpt = input('@')
        z = dict.get(inpt, 'Default text')
        if callable(z):
            z()
        else:
            print(z)
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

You can use the callable() built-in function to test if the given object is callable.

z = dict2.get(inpt, 'Default text')
if callable(z):
    z()
else:
    print(z)
John Gordon
  • 29,573
  • 7
  • 33
  • 58
0

You can use isinstance() to check whether it's a FunctionType or not:

from types import FunctionType

def mainfunction():
    d = {
        'x': secondfunc,
        'y': 'hello world'
    }
    while True:
        inpt = input('@')
        res = d.get(inpt, 'default')
        if isinstance(res, FunctionType):
            res()
        else:
            print(res)

def secondfunc():
    print('hi world')

mainfunction()
S.B
  • 13,077
  • 10
  • 22
  • 49