I have a str object for example: menu = 'install'. I want to run install method from this string. For example when I call menu(some, arguments) it will call install(some, arguments). Is there any way to do that ?
            Asked
            
        
        
            Active
            
        
            Viewed 1.5e+01k times
        
    112
            
            
         
    
    
        Julien
        
- 13,986
- 5
- 29
- 53
 
    
    
        İlker Dağlı
        
- 1,593
- 3
- 13
- 10
- 
                    I changed the duplicate link because https://stackoverflow.com/questions/3061/ is narrowly scoped; this question is looking for `install` in an unspecified namespace (but probably intended to be either the local or global namespace), not as an attribute of a module. – Karl Knechtel Jul 06 '22 at 23:12
3 Answers
152
            If it's in a class, you can use getattr:
class MyClass(object):
    def install(self):
          print "In install"
method_name = 'install' # set by the command line options
my_cls = MyClass()
method = None
try:
    method = getattr(my_cls, method_name)
except AttributeError:
    raise NotImplementedError("Class `{}` does not implement `{}`".format(my_cls.__class__.__name__, method_name))
method()
or if it's a function:
def install():
       print "In install"
method_name = 'install' # set by the command line options
possibles = globals().copy()
possibles.update(locals())
method = possibles.get(method_name)
if not method:
     raise NotImplementedError("Method %s not implemented" % method_name)
method()
 
    
    
        Sam Dolan
        
- 31,966
- 10
- 88
- 84
- 
                    1Thank you for your answer. But what if the method is not in a class? – İlker Dağlı Oct 29 '11 at 02:23
- 
                    Thank you so much sdolan. I have tried with **globals** not **locals** and it works. – İlker Dağlı Oct 29 '11 at 02:31
- 
                    6The latter does not .copy() globals before mutating it, inviting all sorts of trouble. And it has a bug, since it calls the method immediately before checking it, then calls its result again. Also, it's common practise to use a prefix, to prevent calling just ANY element in the namespace (e.g. "do_install()"). – pyroscope Oct 29 '11 at 05:18
- 
                    @pyroscope: Good catch on the globals. I've updated the sample code to do that. I also agree on the prefix, and do that in my own code where it makes sense. I don't know the specifics of the OPs problem, so I'm trying to not jump to any conclusions. – Sam Dolan Oct 30 '11 at 02:27
- 
                    @sdolan , Perfect answer but a minor mistake getattr does not respond with None if attribute does not exista rather it raises an exception so **if not method: raise Exception("Method %s not implemented" % method_name)** is not needed – Sarath Sadasivan Pillai Feb 09 '16 at 10:56
- 
                    @Sarathsp: haha good catch. Only took 4.5 years for someone to catch it ;) – Sam Dolan Feb 20 '16 at 20:31
- 
                    And if you are sure that method exists, you can use: globals().get(method_name)() or locals().get(method_name)() – Alex Benfica Apr 24 '16 at 11:38
- 
                    Your first answer: raise NotImplementedError("Class `{}` does not implement `{}`".format(my_cls.__class__.__name__, method_name) Should be: raise NotImplementedError("Class `{}` does not implement `{}`".format(my_cls.__class__.__name__, method_name)) – Mo Ali Jan 18 '17 at 19:30
- 
                    
- 
                    @AlexBenfica what's the difference between calling by globals and locals? – Nihat Aug 17 '20 at 11:35
- 
                    1@Nihat please refer to this question. https://stackoverflow.com/questions/7969949/whats-the-difference-between-globals-locals-and-vars – Alex Benfica Aug 17 '20 at 19:39
- 
                    
76
            
            
        You can use a dictionary too.
def install():
    print "In install"
methods = {'install': install}
method_name = 'install' # set by the command line options
if method_name in methods:
    methods[method_name]() # + argument list of course
else:
    raise Exception("Method %s not implemented" % method_name)
 
    
    
        concentricpuddle
        
- 777
- 5
- 11
- 
                    11I believe using dictionary is a bit more clean that relying on globals().copy() in accepted answer. – Victor Farazdagi Jan 22 '13 at 02:09
- 
                    1@AgnivaDeSarker Make sure that in setting up your dictionary, you haven't called the function - i.e., that you use only the function name, with no brackets: `{'install': install}` – Hannele Apr 25 '13 at 14:31
- 
                    I like this more, as it easy to pass parameters, and you can control the list of methods easily with dictionalry – Kostanos Feb 26 '15 at 21:35
- 
                    I would prefer this approach to the accepted answer but I can't seem to make it work with class methods. – navjotk Feb 01 '16 at 19:16
- 
                    @navjotk in the declaration of your dictionary: `methods = {'install': self.install}` (or `obj.install`) – Ohad Cohen Oct 06 '16 at 14:38
- 
                    hmm, i tried something similar here but it wasn't working: https://stackoverflow.com/questions/50359442/apply-a-method-from-a-list-of-methods-to-pandas-dataframe – tired May 15 '18 at 22:05
- 
                    If using a dictionary to store the method, the method **must** be defined before the dictionary - as in the method definition must be above the line the dictionary is on or you will get; _"NameError: name 'X' is not defined'_ – myol Nov 26 '18 at 06:51
40
            
            
        Why cant we just use eval()?
def install():
    print "In install"
New method
def installWithOptions(var1, var2):
    print "In install with options " + var1 + " " + var2
And then you call the method as below
method_name1 = 'install()'
method_name2 = 'installWithOptions("a","b")'
eval(method_name1)
eval(method_name2)
This gives the output as
In install
In install with options a b
 
    
    
        Renaud
        
- 16,073
- 6
- 81
- 79
 
    
    
        Husain Khambaty
        
- 740
- 1
- 9
- 22
- 
                    He is asking for a way to call the function with arguments. Can you detail? – Mikaël Mayer Apr 25 '13 at 13:22
- 
                    3
- 
                    6If you are using the above-mentioned strategy, it means that you are dynamically defining your methods/functions, in other words, they can be a lot of things, including malicious code. I suggest you [this article](http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html), and then, never using eval again. When needed, just use `json`. – lucastamoios Jan 16 '17 at 12:03
- 
                    @lucastamoios: Not true at least in case of OP - using predefined strings as function names. – Fr0zenFyr Feb 28 '18 at 12:31
- 
                    How do you suggest building the argument list for an arbitrary list of arguments with `installWithOptions`? Showing the hard coded example certainly doesn't tell the story here. This is all of course ignoring how horrible of a practice using eval is in the first place. I've never seen a legitimate use case for it – Cruncher Mar 20 '18 at 22:01
- 
                    
- 
                    1@Justas Sure. In theory. But now that code is there forever, and a change that seems harmless in another file now turns out to open a giant security hole because of the use of an eval statement. You should build around as few assumption as possible. Because who knows when they'll change. – Cruncher Apr 03 '18 at 13:27
- 
                    2`eval(method_name1)(a,b)` also works. Fair point about safety-- ok for tiny private scripts but do they stay that way? Take great care if the string is coming from a website, for example. It isn't `eval` that's the only problem here-- using `getattr` on a string from an arbitrary source is just as dangerous. – Nic Nov 15 '18 at 02:23
- 
                    **Do not ever use `eval` on data that could possibly ever come from outside the program. It is a security hole that allows whoever creates that data to run arbitrary Python code on your computer. No, you cannot practically sandbox it.** – Karl Knechtel Aug 17 '22 at 07:53