Python输入验证 - 介于20和100之间,没有字母

时间:2014-10-02 04:01:25

标签: 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

为了坚持“高效”和“可重用”代码的概念,我尝试了几种不同的解决方案。

在方法“选择”中找到文本参数的原因:我已经提示指示用户正在与之交互的内容(例如,choice = raw_input(text +“ - &gt;”))。

我的解决方案:

我已尝试使用if语句对text参数进行测试,但对我而言,这对于此解决方案来说太特殊了;因此,不可重复使用。

我尝试过使用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']:#Code

截至目前,我只是在测试整数方面存在问题,同时要坚持可重用性和效率方面。

有没有办法可以看到输入(选项)是否包含任何类型的字母,因此请求更多输入? 有没有办法同时确保map_x / map_y在2&lt; = choice&lt; = 100?

的范围内

非常感谢, Akratix

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

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

2 个答案:

答案 0 :(得分:0)

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

使用以下内容会更简单。您甚至可以自定义字段错误消息,告诉用户他的输入无效,并且通常会更有帮助。

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函数类似,但我们不是采用“菜单”字典,而是采用验证函数。

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 )

答案 1 :(得分:0)

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答案有用(但您可能也需要一些可以进行大小写规范化的方法)