【问题标题】:Most Pythonic way to do input validation [duplicate]进行输入验证的大多数 Pythonic 方式[重复]
【发布时间】:2013-12-30 16:10:05
【问题描述】:

在 Python 中进行用户输入验证最“正确”的 Pythonic 方式是什么?

我一直在使用以下内容:

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

我想这很好而且可读,但我不禁想知道是否没有一些内置函数或我应该使用的东西。

【问题讨论】:

  • 能否显示更多代码?
  • 对不起,我打字前不小心提交了!
  • 我认为你所做的(使用 try~except )还不错,尽管还有其他方法可以完成相同的任务。我没有听说过“Pythonic”方式。这种任务发生在所有其他语言中。
  • 请发some_test函数
  • 完全取决于您所说的“输入验证”(信用卡号、IP 地址、int、float?)以及验证失败时您想要做什么。

标签: python validation user-input assert


【解决方案1】:

对“用户输入”进行这种验证的最Pythonic方法是捕获适当的异常。

示例:

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

允许异常发生在它们所在的位置并允许它们冒泡而不是隐藏它们也是一种很好的做法,这样您就可以清楚地看到 Python Traceback 中出了什么问题。

在这种情况下 验证用户输入 -- 使用 Python 的 Duck Typing 并捕获错误。即:如果它像管道一样,它必须是鸭子。 (如果它像一个 int,它必须是一个 int)。

【讨论】:

  • 换句话说,正是我正在做的事情。 :) 谢谢詹姆斯
  • 正是 :) 我只是想我会扩展它并谈论“Pythonic 方式”及其原因:)
【解决方案2】:

我喜欢装饰器将检查与输入处理的其余部分分开。

#!/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."

编辑:

装饰器或多或少是现有函数(或方法)的包装器。它采用现有函数(在其@decorator 指令下方表示)并为它返回一个“替换”。在我们的例子中,这个替换会在循环中调用原始函数,并在这样做时捕获任何发生的异常。如果没有发生异常,它只是返回原始函数的结果。

【讨论】:

  • 这也相当不错,而且更进一步,有助于更概括它。 Python 装饰器是一个非常强大的工具,可以让您以一种很好的方式组合函数。
  • @Alfe:非常感谢您的回答。然而,尽管热切的谷歌搜索,我对装饰器的工作方式完全一无所知,所以恐怕我并不真正理解你的答案。 :(
  • 我为代码添加了一个小解释,但是当然,在这里解释装饰器已经超出了范围。 Stackoverflow 上有很多关于该主题的问题。
  • 谢谢。我现在有点理解它了。
【解决方案3】:

有点复杂,但可能很有趣:

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)

结果

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.

.

编辑

我找到了一种简化的方法:

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)

【讨论】:

  • 确实很有趣,但我认为对于日常任务来说非常复杂。
  • 有点可怕的是我必须遵循的方式来查找其结果导致断言错误的函数:traceback 对象转换为字符串,正则表达式在此字符串中搜索,将组传递给 glabals 以查找函数对象,获取函数的文档!我没有成功地更直接地从回溯对象中提取函数或其名称。 - 但基本思想可能很有趣:可以简单地添加条件函数,而无需更改 except 块。
  • @henrebotha 我得到了强大的简化
猜你喜欢
  • 2023-03-09
  • 2013-02-20
  • 1970-01-01
  • 2013-02-06
  • 1970-01-01
  • 1970-01-01
  • 2018-01-16
  • 2017-11-24
相关资源
最近更新 更多