我正在尝试使用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答案有用(但您可能也需要进行大小写规范化的东西)