Python输入验证——int在20到100之间,没有字母

  • 本文关键字:之间 验证 int Python python
  • 更新时间 :
  • 英文 :


我正在尝试使用Python验证简单字段的输入。

  • int类型的map_x
  • int类型的map_y
  • bool型障碍物

我在SO上尝试了很多建议。我的代码:

class Map(object):
    def __init__(self):
        # Note: These are defaults.
        # map_x and map_y both have a range of 20 <= x <= 100
        # obstacles = 'Y' || 'N'
        self.map_x = -1
        self.map_y = -1
        self.obstacles = '-'
    def forest_map(self):
        self.map_x = self.choice("Map Width")
        self.map_y = self.choice("Map Length")
        self.obstacles = self.choice("Obstacles (Y/N)")
    def choice(self, text):
        # Code

我尝试了几种不同的解决方案,试图忠于"高效"one_answers"可重复使用"代码的概念。

在方法"choice"中发现文本参数的原因:我已经做出了指示用户正在与什么交互的提示(例如choice=raw_input(text+"->"))。

我的解决方案:

我曾尝试在文本论点中使用if语句进行测试,但对我来说,这对这个解决方案来说太特殊了;因此不可重复使用。

我尝试过使用try/except,但是,即使如此,我的while语句似乎仍在消耗输入,并且没有向map_x和map_y返回值。

我已经尝试过(成功!在上一节中,菜单选择,而不是收集用户偏好)使用如下字典:

# menu is an argument that takes a dictionary.
# dictionary can be found in a list of dictionaries named menu_list. 
# choice is a member of class Menus, and menu_list is defined in Menu's __init__.
def choice(self, menu):
    acceptable = menu
    if menu == self.menu_list[2]:
        choice = raw_input("Choice-> ")
        while choice not in acceptable:
            choice = raw_input("Choice-> ")
        Map().generate(choice)

我只成功地测试了"障碍"。我使用了(而选项不在['Y','Y','N','N']中):#代码

到目前为止,我只在测试整数时遇到了问题,同时又注意到了可重用性和效率。

有没有一种方法可以让我看到输入(选择)是否包含任何类型的字母,从而请求更多的输入?有没有办法同时确保map_x/map_y在2<=的范围内选项<=100?

谢谢大家,Akratix

===编辑2014年2月10日===由于下面的解决方案,我已经提出了两个实现。为了验证应该是整数以及在设定范围内的输入,我使用了以下代码片段:

def map_choice(self, text):
    is_valid = False
    while not is_valid:
        try:
            value = int(raw_input(text + "-> "))
            if 2 > value or 100 < value:
                print "Invalid input!"
                continue
            return value
        except ValueError:
            print "Invalid input!"

为了验证应该是可接受输入"列表"中特定字母的输入,我使用了以下代码片段:

def obstacle_choice(self, text):
    is_valid = False
    while not is_valid:
        value = raw_input(text + "-> ")
        if any(value == x for x in ('Y', 'N', 'y', 'n')):
            return value

您有了一个良好的开端,但不要过于笼统地试图概括一切。您有两个具有不同验证的截然不同的字段,因此使用两个不同的"选择"函数是有意义的。

使用以下内容会简单得多。您甚至可以自定义字段错误消息,告诉用户为什么他的输入无效,并且在一般情况下更有帮助。

def forest_map(self):
    self.map_x = self.map_choice("Map Width")
    self.map_y = self.map_choice("Map Length")
    self.obstacles = self.obstacle_choice("Obstacles (Y/N)")
def map_choice(self, message)
    # here we use try except to make sure its an integer
    try:
        value = int(raw_input(message))
    except ValueError:
        print "Invalid input!"
        return -1
    # check range
    if 20 > value or 100 < value:
        print "Invalid input!"
        return -1
    return value
def obstacle_choice(self, message):
    value = raw_input(message)
    # check if its an acceptable answer
    if any( value == x for x in ('Y', 'N', 'y', 'n') ):
        return value
    print "Invalid input!"
    return -1

或者,如果您有很多字段,那么使用一个以验证函数为参数的选择函数可能是值得的。类似于您的第二个choice函数,但我们采用的不是"菜单"dict,而是验证函数。

def forest_map(self):
    valid_map = lambda x: 20 <= int(x) <= 100
    valid_obstacle = lambda x: any( x == y for y in ('Y', 'N', 'y', 'n') )
    # the choice function will guarantee its safe to use int on the result
    self.map_x = int(self.choice("Map Width", valid_map))
    self.map_y = int(self.choice("Map Length", valid_map))
    self.obstacles = self.choice("Obstacles (Y/N)", valid_obstacle)
def choice(self, message, validate):
    """
    Prompt a user for input and validate the input
    Args:
        message (str): Message to display at prompt
        validate (callable): callable of one parameter to validate input
    Returns:
        str: A valid user input
    """
    is_valid = False
    while not is_valid:
        # prompt for input
        value = raw_input(message)
        # validate input with our validation function
        # if validate(value) returns True, it ends the loop
        try:
            is_valid = validate(value)
        # maybe the validation function throws an exception
        # its best to catch the specific error class, but I'll use Exception for simplicity
        except Exception:
            is_valid = False
    return True

最后,关于检查输入是否包含任何字母。可以使用isalpha方法,该方法检查字符串中的每个字符是否都是字母。要检查字符串中的任何字符是否为字母,可以使用此选项。

value = raw_input('>')
contains_letters = any( c.isalpha() for c in value )

choice函数一个额外的参数,我通常称之为type(尽管与内置函数发生冲突),这是一个可调用的参数,它将转换和验证参数。

IntRange(2, 100) 一样使用此示例

class IntRange(object):
    def __init__(self, min, max):
        self.min = min
        self.max = max
    def __call__(self, s):
        i = int(s) # throws
        if self.min <= i <= self.max:
            return i
        raise ValueError('%d is out of range' % i)

我实现的更多类型如下:https://github.com/o11c/attoconf/blob/master/attoconf/types.py;enum类型可能对y/n答案有用(但您可能也需要进行大小写规范化的东西)

最新更新