2014-10-02 38 views
1

我想驗證輸入使用Python的簡單字段。 int類型的Python輸入驗證 - int在20和100之間,沒有字母

  • 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 

我嘗試了幾種不同的解決方案,試圖保持「高效」和「可重用」代碼的概念。

在方法「選擇」中找到text參數的原因:我已提示用戶正在與之交互(例如,choice = raw_input(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']:#代碼

截至目前,我只有在測試整數的問題,但保持真實可重用性和效率的方面

有沒有一種方法,我可以看到,如果輸入(選擇)包含任何類型的字母,並因此,請求更多的輸入? 有沒有一種方法,我可以同時,確保該map_x/map_y是的範圍內2 < =選擇< = 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 

回答

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) 
+0

Kalhartt,非常感謝您提供的解決方案。我有一個問題: 在第二種解決方案中,採用'self.map_x ='行。 我很困惑,因爲valid_map沒有被傳入'choice',即代碼不是int(self.choice(「Map Width」,valid_map))。 爲什麼lambda函數作爲int()的參數傳入? 我誤解了使用lambda函數嗎? 非常感謝! – Akratix 2014-10-03 00:53:44

+0

@Akratix你是絕對正確的,這是我的錯誤,應該是'int(self.choice(「Map Width」,valid_map))'。好,我會編輯並修復! – kalhartt 2014-10-03 01:14:36

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的回答很有用(但您可能需要一些可以正常化的東西)