<p>最简单的方法是将<code>input</code>方法放入while循环中。当输入错误时使用<a href="https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops" rel="noreferrer">^{<cd2>}</a>,当您满意时使用<code>break</code>退出循环。</p>
<h2>当您的输入可能引发异常时</h2>
<p>使用<a href="https://docs.python.org/3/tutorial/errors.html#handling-exceptions" rel="noreferrer">^{<cd4>} and ^{<cd5>}</a>检测用户何时输入无法分析的数据。</p>
<pre><code>while True:
try:
# Note: Python 2.x users should use raw_input, the equivalent of 3.x's input
age = int(input("Please enter your age: "))
except ValueError:
print("Sorry, I didn't understand that.")
#better try again... Return to the start of the loop
continue
else:
#age was successfully parsed!
#we're ready to exit the loop.
break
if age >= 18:
print("You are able to vote in the United States!")
else:
print("You are not able to vote in the United States.")
</code></pre>
<h2>实现自己的验证规则</h2>
<p>如果要拒绝Python可以成功解析的值,可以添加自己的验证逻辑。</p>
<pre><code>while True:
data = input("Please enter a loud message (must be all caps): ")
if not data.isupper():
print("Sorry, your response was not loud enough.")
continue
else:
#we're happy with the value given.
#we're ready to exit the loop.
break
while True:
data = input("Pick an answer from A to D:")
if data.lower() not in ('a', 'b', 'c', 'd'):
print("Not an appropriate choice.")
else:
break
</code></pre>
<h2>结合异常处理和自定义验证</h2>
<p>以上两种技术都可以组合成一个循环。</p>
<pre><code>while True:
try:
age = int(input("Please enter your age: "))
except ValueError:
print("Sorry, I didn't understand that.")
continue
if age < 0:
print("Sorry, your response must not be negative.")
continue
else:
#age was successfully parsed, and we're happy with its value.
#we're ready to exit the loop.
break
if age >= 18:
print("You are able to vote in the United States!")
else:
print("You are not able to vote in the United States.")
</code></pre>
<h2>将其全部封装在函数中</h2>
<p>如果需要向用户询问许多不同的值,那么将此代码放入函数中可能会很有用,因此不必每次都重新键入它。</p>
<pre><code>def get_non_negative_int(prompt):
while True:
try:
value = int(input(prompt))
except ValueError:
print("Sorry, I didn't understand that.")
continue
if value < 0:
print("Sorry, your response must not be negative.")
continue
else:
break
return value
age = get_non_negative_int("Please enter your age: ")
kids = get_non_negative_int("Please enter the number of children you have: ")
salary = get_non_negative_int("Please enter your yearly earnings, in dollars: ")
</code></pre>
<h3>总而言之</h3>
<p>您可以将此思想扩展为一个非常通用的输入函数:</p>
<pre><code>def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
if min_ is not None and max_ is not None and max_ < min_:
raise ValueError("min_ must be less than or equal to max_.")
while True:
ui = input(prompt)
if type_ is not None:
try:
ui = type_(ui)
except ValueError:
print("Input type must be {0}.".format(type_.__name__))
continue
if max_ is not None and ui > max_:
print("Input must be less than or equal to {0}.".format(max_))
elif min_ is not None and ui < min_:
print("Input must be greater than or equal to {0}.".format(min_))
elif range_ is not None and ui not in range_:
if isinstance(range_, range):
template = "Input must be between {0.start} and {0.stop}."
print(template.format(range_))
else:
template = "Input must be {0}."
if len(range_) == 1:
print(template.format(*range_))
else:
print(template.format(" or ".join((", ".join(map(str,
range_[:-1])),
str(range_[-1])))))
else:
return ui
</code></pre>
<p>用法如下:</p>
<pre><code>age = sanitised_input("Enter your age: ", int, 1, 101)
answer = sanitised_input("Enter your answer: ", str.lower, range_=('a', 'b', 'c', 'd'))
</code></pre>
<h2>常见的陷阱,以及为什么要避免它们</h2>
<h3>冗余语句的冗余使用
<p>这种方法有效,但通常被认为是低劣的风格:</p>
<pre><code>data = input("Please enter a loud message (must be all caps): ")
while not data.isupper():
print("Sorry, your response was not loud enough.")
data = input("Please enter a loud message (must be all caps): ")
</code></pre>
<p>它最初看起来很有吸引力,因为它比<code>while True</code>方法短,但它违反了软件开发的<a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself" rel="noreferrer">Don't Repeat Yourself</a>原则。这会增加系统中出现错误的可能性。如果您想通过将<code>input</code>更改为<code>raw_input</code>,但意外地只更改上面的第一个<code>input</code>,将backport更改为2.7,该怎么办?只是在等待发生。</p>
<h3>递归将破坏堆栈</h3>
<p>如果您刚刚学习了递归,那么您可能会尝试在<code>get_non_negative_int</code>中使用它,以便可以处理while循环。</p>
<pre><code>def get_non_negative_int(prompt):
try:
value = int(input(prompt))
except ValueError:
print("Sorry, I didn't understand that.")
return get_non_negative_int(prompt)
if value < 0:
print("Sorry, your response must not be negative.")
return get_non_negative_int(prompt)
else:
return value
</code></pre>
<p>这在大多数情况下似乎工作正常,但是如果用户输入无效数据的次数足够多,脚本将以<code>RuntimeError: maximum recursion depth exceeded</code>结束。你可能认为“没有傻瓜会连续犯1000个错误”,但你低估了傻瓜的聪明才智!</p>