【问题标题】:How to handle both integer and string from raw_input?如何处理 raw_input 中的整数和字符串?
【发布时间】:2012-01-22 14:07:20
【问题描述】:

仍在尝试理解 python。它与php是如此不同。

我将选项设置为整数,问题出在我的菜单上,我也需要使用字母。

如何同时使用整数和字符串?
为什么我不能设置为字符串而不是整数?

def main(): # Display the main menu
    while True:
        print
        print "  Draw a Shape"
        print "  ============"
        print
        print "  1 - Draw a triangle"
        print "  2 - Draw a square"
        print "  3 - Draw a rectangle"
        print "  4 - Draw a pentagon"
        print "  5 - Draw a hexagon"
        print "  6 - Draw an octagon"
        print "  7 - Draw a circle"
        print
        print "  D - Display what was drawn"
        print "  X - Exit"
        print

        choice = raw_input('  Enter your choice: ')

        if (choice == 'x') or (choice == 'X'):
            break

        elif (choice == 'd') or (choice == 'D'):
            log.show_log()

        try:
            choice = int(choice)
            if (1 <= choice <= 7):

                my_shape_num = h_m.how_many()
                if ( my_shape_num is None): 
                    continue

                # draw in the middle of screen if there is 1 shape to draw
                if (my_shape_num == 1):
                    d_s.start_point(0, 0)
                else:
                    d_s.start_point()
                #
                if choice == 1: 
                    d_s.draw_triangle(my_shape_num) 
                elif choice == 2: 
                    d_s.draw_square(my_shape_num) 
                elif choice == 3:             
                    d_s.draw_rectangle(my_shape_num) 
                elif choice == 4:             
                    d_s.draw_pentagon(my_shape_num) 
                elif choice == 5:             
                    d_s.draw_hexagon(my_shape_num) 
                elif choice == 6:             
                    d_s.draw_octagon(my_shape_num) 
                elif choice == 7: 
                    d_s.draw_circle(my_shape_num)

                d_s.t.end_fill() # shape fill color --draw_shape.py-- def start_point

            else:
                print
                print '  Number must be from 1 to 7!'
                print

        except ValueError:
            print
            print '  Try again'
            print

【问题讨论】:

  • 不清楚是什么问题;菜单方面似乎工作正常:输入 X 时执行 break,输入 D 时执行 log.show_log(),输入 1..7 中的整数时分配 my_shape_num。
  • 问题是:如果选择是D;我得到 log.show_log() 然后我得到错误消息'再试一次'
  • 所以问题与string/int无关;它是你的“尝试”应该被包裹在一个“其他”中。

标签: python user-input


【解决方案1】:

让我用另一个问题来回答你的问题:
真的有必要混合字母和数字吗?
它们不能都是字符串吗?

好吧,让我们走很远的路,看看程序在做什么:

  1. 显示主菜单
  2. 询问/接收用户输入
    • 如果有效:ok
    • 如果不是:打印错误消息并重复
  3. 现在我们有一个有效的输入
    • 如果是一封信:做一个特殊的任务
    • 如果是数字:调用正确的绘图函数

第 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 非常简单,所以没有必要解释它的作用,但我们稍后会看到将这段代码放入单独的函数中的好处。

第 2 点。 这将通过循环来完成:

options = ['1', '2', 'D', 'X']

while 1:
    choice = raw_input('  Enter your choice: ')
    if choice in options:
        break
    else:
        print 'Try Again!'

第 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,而是dict,所以如果你像if choice in options一样简单地迭代它,你的迭代就在keys em>:['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

对于options,我们需要OrderedDict 而不是dict,因为OrderedDict 顾名思义保持其项目的顺序(查看official doc)。所以我们有:

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 类并从中继承将是完美的。

【讨论】:

  • 相当彻底,但我注意到您在 printraw_input 声明中混合了 2.x 和 3.x。 (也就是说,您在带有 3.x 的 print() 的脚本中使用了 raw_input。)
  • @Edwin:脚本在python 2.x 中运行。一开始有几个print(),但由于里面只有一个字符串,你不会注意到python-2.x('Try Again') == 'Try Again'之间的区别。就像括号在文本上而不是在print 上一样。无论如何,我会修复它们以消除任何疑问:)
  • 那么我是正确的。你在 SO 上学到的另一个奇怪的东西。
  • 使用OrderedDict 真是太好了。使用普通的dict 并对键进行排序也可以在这里使用,但OrderedDict 肯定更好。
【解决方案2】:

我不完全清楚你在这里问什么。 raw_input() 总是返回 str 类型。如果您想将用户输入自动转换为 int 或其他(简单)类型,您可以使用 input() 函数,它会执行此操作。

您已选择让用户输入字母或数字,您同样可以将“字母”选项分配给菜单中的数字。或者,您可以更多地利用try/except,例如:

try:
    choice = int(user_input)
    if choice == 1:
        # do something
    elif ...
except ValueError: # type(user_input) != int
    if choice == 'X' or choice == 'x':
        # do something
    elif ...
    else:
        print 'no idea what you want' # or print menu again

【讨论】:

    【解决方案3】:

    我相信你的代码可以简化一点:

    def main():
        while 1:
            print
            print "  Draw a Shape"
            print "  ============"
            print
            print "  1 - Draw a triangle"
            print "  2 - Draw a square"
            print "  3 - Draw a rectangle"
            print "  4 - Draw a pentagon"
            print "  5 - Draw a hexagon"
            print "  6 - Draw an octagon"
            print "  7 - Draw a circle"
            print
            print "  D - Display what was drawn"
            print "  X - Exit"
            print
            choice = raw_input('  Enter your choice: ').strip().upper()
            if choice == 'X':
                break
            elif choice == 'D':
                log.show_log()
            elif choice in ('1', '2', '3', '4', '5', '6', '7'):
                my_shape_num = h_m.how_many()
                if my_shape_num is None:
                    continue
                elif my_shape_num == 1:
                    d_s.start_point(0, 0)
                else:
                    d_s.start_point()
                if choice == '1':
                    d_s.draw_triangle(my_shape_num)
                elif choice == '2':
                    d_s.draw_square(my_shape_num)
                elif choice == '3':
                    d_s.draw_rectangle(my_shape_num)
                elif choice == '4':
                    d_s.draw_pentagon(my_shape_num)
                elif choice == '5':
                    d_s.draw_hexagon(my_shape_num)
                elif choice == '6':
                    d_s.draw_octagon(my_shape_num)
                elif choice == '7':
                    d_s.draw_circle(my_shape_num)
                d_s.t.end_fill()
            else:
                print
                print '  Invalid choice: ' + choice
                print
    

    【讨论】:

    • 添加.lower()并使用choice in [str(i) for i in range(1, 7)]就完美了。
    • @RobWouters 感谢您的建议。我添加了lower(),但我会坚持使用元组('1', ...),对于刚刚学习编程的人来说更容易理解
    • +1 为简单起见。由于数字输入实际上并未用于数字运算,因此只需将其保留为字符串,以便您始终拥有一个字符串并相应地进行操作。另一种简化检查的方法,仍然很容易理解(但不太灵活!!!)是choice in '1234567'in 是字符串进行子字符串搜索的特殊情况。
    • @KarlKnechtel choice in '1234567' 更简单但会导致问题,例如,如果用户键入23
    【解决方案4】:

    如何同时使用整数和字符串?为什么我不能设置为字符串而不是整数?

    嗯,string formatting 是一个非常有用的东西:

    >>> a_string = "Hi, I'm a string and I'm"
    >>> an_integer = 42
    >>> another_string = "milliseconds old"
    >>> we_are_the_champions = "%s %d %s" % (a_string, an_integer, another_string)
    >>> we_are_the_champions
    "Hi, I'm a string and I'm 42 milliseconds old"
    

    你甚至可以把那个整数扔进字符串:

    >>> champions_are_here = "Hi, I'm a string and I'm even older, I'm %d milliseconds old" % 63
    >>> champions_are_here
    "Hi, I'm a string and I'm even older, I'm 63 milliseconds old"
    

    【讨论】:

      【解决方案5】:

      您可以将“字母选项”放在 except 块中。如果输入无法转换为整数,则执行该块,例如如果是字母。


      不过,让try 块尽可能小是一种很好的习惯。所以最好这样做:

      try:
          choice = int(choice)
      except ValueError:
          choice = choice.lower() # Now you don't have to check for uppercase input
      

      然后您可以检查选择是否是inttype(choice) == int

      【讨论】:

      • 最后一点很重要。根据 OP 提交的代码,无需将类型从 string 更改为 int
      • @sgallen,在我意识到如果输入是整数时他会做一些一般的事情,我实际上已经删除了那个部分。
      • 只有当输入的字符串是('1', '2', '3', '4', '5', '6', '7') 之一时才需要一般的东西,当您可以更快地确定choice属于定义的可迭代对象。我正在考虑用户输入88 的情况,这将传递您的try,当您可以直接跳到'Number must be from 1 to 7!' 行时,您将不必要地单步执行代码。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-23
      • 2020-07-09
      • 1970-01-01
      • 2022-01-14
      • 1970-01-01
      相关资源
      最近更新 更多