Most Pythonic way to do input validation [duplicate]

霸气de小男生 提交于 2019-12-12 10:45:14

问题


What is the most "correct", Pythonic way to do user input validation in Python?

I've been using the following:

while True:
    stuff = input("Please enter foo: ")
    try:
        some_test(stuff)
        print("Thanks.")
        break
    except SomeException:
        print("Invalid input.")

Which is nice and readable, I suppose, but I can't help wondering if there isn't some built-in function or something I should be using instead.


回答1:


I like decorators to separate the checking from the rest of the input handling.

#!/usr/bin/env python

def repeatOnError(*exceptions):
  def checking(function):
    def checked(*args, **kwargs):
      while True:
        try:
          result = function(*args, **kwargs)
        except exceptions as problem:
          print "There was a problem with the input:"
          print problem.__class__.__name__
          print problem
          print "Please repeat!"
        else: 
          return result
    return checked
  return checking

@repeatOnError(ValueError)
def getNumberOfIterations():
  return int(raw_input("Please enter the number of iterations: "))

iterationCounter = getNumberOfIterations()
print "You have chosen", iterationCounter, "iterations."

EDIT:

A decorator is more or less a wrapper for an existing function (or method). It takes the existing function (denoted below its @decorator directive) and returns a "replacement" for it. This replacement in our case calls the original function in a loop and catches any exception happening while doing so. If no exception happens, it just returns the result of the original function.




回答2:


The most Pythonic way to do this kind of validation of "User INput" is to catch an appropriate exception.

Example:

def get_user_input():
    while True:
        try:
            return int(input("Please enter a number: "))
        except ValueError:
            print("Invalid input. Please try again!")

n = get_user_input()
print("Thanks! You entered: {0:d}".format(n))

It's also good practice to allow exceptions occur where they lie and allow them to bubble up rather than hide them so you can clearly see what's going wrong in a Python Traceback.

In this case Validating User Input -- Use Python's Duck Typing and catch the error. i.e: If it acts like a duct, it must be a duck. (If it acts like an int, it must be an int).




回答3:


A bit complicated, but may be interesting:

import re
from sys import exc_info,excepthook
from traceback import format_exc

def condition1(stuff):
    '''
    stuff must be the string of an integer'''
    try:
        i = int(stuff)
        return True
    except:
        return False

def condition2(stuff):
    '''
    stuff is the string of an integer
    but the integer must be in the range(10,30)'''
    return int(stuff) in xrange(10,30)

regx = re.compile('assert *\( *([_a-z\d]+)')

while True:
    try:
        stuff = raw_input("Please enter foo: ")
        assert(condition1(stuff))
        assert (  condition2(stuff))
        print("Thanks.")
        break
    except AssertionError:
        tbs = format_exc(exc_info()[0])
        funky = globals()[regx.search(tbs).group(1)]
        excepthook(exc_info()[0], funky.func_doc, None)

result

Please enter foo: g
AssertionError: 
    stuff must be the string of an integer
Please enter foo: 170
AssertionError: 
    stuff is the string of an integer
    but the integer must be in the range(10,30)
Please enter foo: 15
Thanks.

.

EDIT

I found a way to simplify:

from sys import excepthook

def condition1(stuff):
    '''
    stuff must be the string of an integer'''
    try:
        int(stuff)
        return True
    except:
        return False

def another2(stuff):
    '''
    stuff is the string of an integer
    but the integer must be in the range(10,30)'''
    return int(stuff) in xrange(10,30)

tup = (condition1,another2)

while True:
    try:
        stuff = raw_input("Please enter foo: ")
        for condition in tup:
            assert(condition(stuff))
        print("Thanks.")
        break
    except AssertionError:
        excepthook('AssertionError', condition.func_doc, None)


来源:https://stackoverflow.com/questions/20540274/most-pythonic-way-to-do-input-validation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!