让我用另一个问题来回答你的问题:
真的有必要混合字母和数字吗?
它们不能都是字符串吗?
好吧,让我们长远来看一下程序在做什么:
- 显示主菜单
- Ask/receive the user input
- Now we have a valid input
- 如果是字母:执行特殊任务
- 如果是数字:调用正确的绘图函数
Point 1.让我们为此创建一个函数:
def display_menu():
menu_text = """\
Draw a Shape
============
1 - Draw a triangle
2 - Draw a square
D - Display what was drawn
X - Exit"""
print menu_text
display_menu
非常简单,因此无需解释它的作用,但稍后我们将看到将此代码放入单独函数中的优点。
Point 2.这将通过循环完成:
options = ['1', '2', 'D', 'X']
while 1:
choice = raw_input(' Enter your choice: ')
if choice in options:
break
else:
print 'Try Again!'
Point 3.好吧,再想一想,也许特殊任务并不是那么特别,所以让我们将它们也放入一个函数中:
def exit():
"""Exit""" # this is a docstring we'll use it later
return 0
def display_drawn():
"""Display what was drawn"""
print 'display what was drawn'
def draw_triangle():
"""Draw a triangle"""
print 'triangle'
def draw_square():
"""Draw a square"""
print 'square'
现在让我们把它们放在一起:
def main():
options = {'1': draw_triangle,
'2': draw_square,
'D': display_drawn,
'X': exit}
display_menu()
while 1:
choice = raw_input(' Enter your choice: ').upper()
if choice in options:
break
else:
print 'Try Again!'
action = options[choice] # here we get the right function
action() # here we call that function
开关的关键在于options
现在不再是list
but a dict
,所以如果你只是像这样迭代它if choice in options
你的迭代是在keys:['1', '2', 'D', 'X']
,但如果你这样做options['X']
你得到了退出函数(是不是太棒了!)。
现在让我们再次改进,因为维护主菜单消息和options
字典不太好,一年后我可能会忘记更改一个或另一个,我不会得到我想要的东西,我很懒,我不想做两次同样的事情,等等......
那么为什么不通过options
字典到display_manu
然后让display_menu
使用文档字符串完成所有工作__doc__
生成菜单:
def display_menu(opt):
header = """\
Draw a Shape
============
"""
menu = '\n'.join('{} - {}'.format(k,func.__doc__) for k,func in opt.items())
print header + menu
我们需要OrderedDict
代替dict
for options
, 因为OrderedDict
顾名思义,保持其项目的顺序(看看官方文档)。所以我们有:
def main():
options = OrderedDict((('1', draw_triangle),
('2', draw_square),
('D', display_drawn),
('X', exit)))
display_menu(options)
while 1:
choice = raw_input(' Enter your choice: ').upper()
if choice in options:
break
else:
print 'Try Again!'
action = options[choice]
action()
请注意,您必须设计您的操作,以便它们都具有相同的签名(无论如何它们应该是这样的,它们都是操作!)。您可能想使用可调用对象作为操作:带有以下内容的类实例__call__
实施的。创建基地Action
类并继承它在这里就很完美了。