Making a menu in Python

Possible Duplicate:
Calling a function from a string with the function's name in Python

I think I could write some terrible code that would do this, but I'd much rather see the 'clean version'.

What seems the good approach to me, is to make a dict that holds the various functions that a given object can use. Then when the user is instructed to tell the object what it's doing, it spits out a menu based on that dict.

I searched around a bit and didn't really see something that applied to me so I figured I'd give it a try. Well, it didn't work.

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()

In case it isn't obvious, the program gives TypeError whenever I enter something which the if-else sees to be True - in this case, entering either 'foo' or 'bar'. Here's the thing, is that I know I could just write a big long ugly if-else thing here and make this example work - but I want to be able to just append/remove from self.cmds to alter the object's functionality. Hence the third function Junk(); Stick can't access 'Junk()' from the current dict-menu, but with a little self.cmds.append action I want it to be able to.

Freaking Python, how do they work? Is this the right way to go about this, or is there a simpler method?

EDIT: My answer was found in the magic of getattr. Thanks cdhowie. The trick was to change the while loop to have this bit: result = getattr(self, cmd)()

I know now my next mission is to finally figure out what getattr() actually does. Forgive my noob status, heh, I know not what I code :)

FINAL EDIT: while cdhowie's example works with the original program, I have since found that ders' answer allows me to do things functionally that I wouldn't have been able to do with getattr(); ders' solution made it easier for me to use functions in other objects in Man's init - I think that's called 'object composition' right? At any rate getattr() would AttributeError any functions added to self.cmds from anywhere but Man. Or I could just be doing it weird again. But suffice to say, ders FTW.


In your example Man.cmds is a list not a dictionary. So they TypeError is raised when the string in the self.cmds list is called as a function.

Create a dictionary with the function name as a string paired with the function itself.

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

Within your Menu function, check if the user has entered in a valid function name. If so pull it out of the dictionary and call it.

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

To dynamically add the junk function, you could then update cmds:

Stick.cmds.update({'junk':Stick.junk})
链接地址: http://www.djcxy.com/p/55170.html

上一篇: 在Python中使用getattr调用一个函数

下一篇: 在Python中制作菜单