用Python制作菜单

时间:2011-08-31 02:02:44

标签: python dictionary menu

  

可能重复:
  Calling a function from a string with the function's name in Python

我想我可以编写一些可怕的代码,但我更愿意看到'干净版'。

对我来说,最好的方法是创建一个包含给定对象可以使用的各种函数的dict。然后当指示用户告诉对象它正在做什么时,它会根据该字典吐出一个菜单。

我搜索了一下,并没有真正看到适用于我的东西,所以我想我会尝试一下。嗯,它不起作用。

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看到为True的东西,程序就会给出TypeError - 在这种情况下,输入'foo'或'bar'。 这就是我知道我可以在这里写一个很长的丑陋的if-else的东西并使这个例子工作 - 但是我希望能够从self.cmds中追加/删除来改变对象的功能。因此第三个函数Junk(); Stick无法从当前的dict-menu访问'Junk()',但是我希望它能够通过一些self.cmds.append操作。

吓坏Python,它们如何运作?这是解决这个问题的正确方法,还是有更简单的方法?

编辑:我的回答是在getattr的魔力中找到的。谢谢cdhowie。诀窍是改变while循环以获得这个位:result = getattr(self,cmd)()

我现在知道我的下一个任务是终于找出getattr()实际上做了什么。请原谅我的菜鸟状态,嘿,我不知道我的代码是什么:)

最终编辑:虽然cdhowie的例子适用于原始程序,但我发现ders的回答允许我在功能上做一些我无法用getattr()做的事情; ders的解决方案使我更容易在Man的 init 中使用其他对象中的函数 - 我认为这称为'对象组合'对吗?无论如何,getattr()会将AttributeError从除man之外的任何地方添加到self.cmds中的任何函数。或者我可能会再次做到这一点。但是,足以说,FTW。

1 个答案:

答案 0 :(得分:2)

在您的示例中,Man.cmds是一个列表而不是字典。因此,当self.cmds列表中的字符串作为函数调用时,会引发TypeError。

创建一个字典,其函数名称为与函数本身配对的字符串。

    def __init__(self):
        self.cmds = {'foo':self.foo, 'bar':self.bar}

在菜单功能中,检查用户是否输入了有效的功能名称。如果是这样,请将其从字典中拉出并调用它。

            if cmd in self.cmds:
                command = self.cmds[cmd]
                command()
            else:
                pass

要动态添加垃圾功能,您可以update cmds:

Stick.cmds.update({'junk':Stick.junk})