Possible Duplicate:
Calling a function from a string with the function's name in Python
我想我可以写一些糟糕的代码来实现这一点,但是我更愿意看到"干净的版本"。
在我看来,最好的方法是创建一个dict,它包含给定对象可以使用的各种函数。然后,当用户被指示告诉对象它在做什么时,它会根据该dict吐出一个菜单。
我到处找了一下,并没有真正发现适合我的东西,所以我想我应该试一试。但它没有成功。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Man(object): def __init__(self): self.cmds = ['foo', 'bar'] def foo(self): print"Foo called." def bar(self): print"Bar called." def junk(self): print"Junk called." ##not in dict, on purpose, will explain def menu(self): while True: print"List of actions:" for acts in self.cmds: print acts cmd = raw_input(">") if cmd in self.cmds: cmd() ##doesn't work. ##neither did self.cmd() (got AttributeError, obviously) result = getattr(self, cmd)() ## this works! thanks cdhowie else: pass Stick = Man() Stick.menu() |
如果不明显的话,每当我输入if-else认为正确的东西时,程序就会给出类型错误——在本例中,输入"foo"或"bar"。事情是这样的,我知道我可以在这里写一个又长又丑的if-else来让这个例子工作,但是我想能够从self中添加/删除。更改对象的功能。因此,第三个函数Junk();Stick不能从当前的dict-menu中访问"Junk()",但可以使用一个小小的self.cmds。追加动作,我希望它能够。
该死的蟒蛇,它们是怎么工作的?这是正确的方法,还是有更简单的方法?
编辑:我的答案是在getattr的魔力中找到的。谢谢cdhowie。诀窍是将while循环更改为:result = getattr(self, cmd)()
现在我知道我的下一个任务是最终弄清楚getattr()实际上做了什么。请原谅我的新手身份,呵呵,我不知道我在写什么:)
最后编辑:虽然cdhowie的示例与原始程序兼容,但我发现ders的答案允许我在功能上做一些getattr()无法做到的事情;ders的解决方案让我更容易在其他对象中使用函数在Man的init中,我想这叫做对象合成,对吧?无论如何,getattr()都会将任何添加到self的函数归为AttributeError。除了人类,其他地方都有cmds。或者我又做了一件奇怪的事。但只要说,德斯FTW。
以你为例。cmds是一个列表,而不是字典。当self中的字符串时,它们会引发TypeError。将cmds列表作为函数调用。
创建一个字典,将函数名作为字符串与函数本身配对。
1 2 | def __init__(self): self.cmds = {'foo':self.foo, 'bar':self.bar} |
在菜单函数中,检查用户是否输入了有效的函数名。如果是这样,就从字典中找出它并调用它。
1 2 3 4 5 | if cmd in self.cmds: command = self.cmds[cmd] command() else: pass |
要动态添加junk函数,可以使用
1 | Stick.cmds.update({'junk':Stick.junk}) |