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 ?
3 Answers
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()
12 Comments
İlker Dağlı
Thank you for your answer. But what if the method is not in a class?
İlker Dağlı
Thank you so much sdolan. I have tried with globals not locals and it works.
pyroscope
The 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()").
Sam Dolan
@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.
Alex Benfica
@Nihat please refer to this question. stackoverflow.com/questions/7969949/…
|
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)
7 Comments
Victor Farazdagi
I believe using dictionary is a bit more clean that relying on globals().copy() in accepted answer.
Hannele
@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}Kostanos
I like this more, as it easy to pass parameters, and you can control the list of methods easily with dictionalry
navjotk
I would prefer this approach to the accepted answer but I can't seem to make it work with class methods.
Ohad Cohen
@navjotk in the declaration of your dictionary:
methods = {'install': self.install} (or obj.install) |
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
9 Comments
Mikaël Mayer
He is asking for a way to call the function with arguments. Can you detail?
Husain Khambaty
Yup it works with arguments as well in the same manner.
lucastamoios
If 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, and then, never using eval again. When needed, just use
json.Cruncher
@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.
Kim
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. |
installin an unspecified namespace (but probably intended to be either the local or global namespace), not as an attribute of a module.