在Python中读取一系列输入/输出
为了我的应用程序,我需要打印出一系列的输出,然后接受用户的输入。有什么好的方法可以做到这一点呢?
比如说:
print '1'
x = raw_input()
print '2'
y = raw_input()
像这样,但我需要重复至少10次。我唯一担心的是这样做会让代码变得不太容易阅读。
我该怎么做呢?我是不是应该像这样创建一个函数:
def printOut(string):
print string
或者有没有更好的方法呢?
3 个回答
如果你在读取多个字段的数据,可能会想要这样做:
field_defs = [
('name', 'Name'),
('dob' , 'Date of Birth'),
('sex' , 'Gender'),
#...
]
# Figure out the widest description.
maxlen = max(len(descr) for (name, descr) in field_defs)
fields = {}
for (name, descr) in field_defs:
# Pad to the widest description.
print '%-*s:' % (maxlen, descr),
fields[name] = raw_input()
# You should access the fields directly from the fields variable.
# But if you really want to access the fields as local variables...
locals().update(fields)
print name, dob, sex
“代码可读性差了10倍...”
其实并不是这样。你需要提供更复杂的例子。
20行代码根本不算什么。为了避免写这20行代码,你可能会写出超过20行的代码。
另外,你也应该看看raw_input
的说明。可以在这里查看:http://docs.python.org/library/functions.html#raw_input
它会显示一个提示信息。你写的那四行代码实际上是:
x = raw_input( '1' )
y = raw_input( '2' )
这个代码已经不能再简化了。
首先要说明的是,raw_input()
可以接受一个可选的参数,也就是提示信息。
关于更广泛的问题,一个简单的方法是创建一个类,这个类定义了你表单的元素,并提供输入、验证以及后续处理或输出的功能。
通过这样的类,可以创建实例(也就是对象),并进行收集、存储等操作。
这样的做法其实并不复杂,像下面这样就可以了:
#!/usr/bin/python
# I use /usr/bin/env python; but making SO's syntax highlighter happy.
class generic_form:
def __init__(self, element_list):
self.form_elements = element_list
self.contents= dict()
def fill_it_in(self):
for prompt in self.form_elements:
self.contents[prompt] = raw_input(prompt)
def get(self, item):
return self.contents[item]
def print_it(self):
for each in self.form_elements:
print each, self.contents[each]
if __name__ == '__main__':
sample_fields = ("Given Name: ",
"Surname: ",
"Date of Birth: ",
"Notes: ")
example = generic_form(sample_fields)
print "Fill in my form:"
example.fill_it_in()
print
print "Please review your input:"
example.print_it()
# store(:%s, %s: %s" % (example.get('Surname: '), \
# example.get('Given Name: '), example.get('Notes: '))
主要的代码只有十几行,定义了一个通用的表单类,具备输入和输出的功能(还有一个简单的get()
方法,用于进一步说明)。
这个例子其余部分只是创建了一个实例,并展示了它的使用方式。
因为我的generic_form
类是通用的,所以我们需要提供一个字段名称的列表,这些字段需要填写。这个名称在后续访问时会用到(可以参考get()
方法的例子)。个人来说,我不会这样做,我会提供一个简短的字段名称和提示,类似于Marcelo的例子。不过,我希望这个例子尽可能简短,以便传达主要观点。
(最后的注释是一个假设的“store()”函数调用,用于将数据存储以备后用。)
这是最简单的方法。然而,你很快会发现,拥有一个更丰富的类,能够对每个字段进行验证,并且有不同的类来格式化和输出这些实例,以及不同的输入类,会更加有用。“电传”输入(就是Python的raw_input()
内置函数提供的)是最简单的形式(主要是为了简单和能够通过shell重定向处理文件)。你还可以支持使用GNU的readline
(已经作为Python的标准库包含),还有curses支持(同样包含),你甚至可以想象编写一些HTML包装和CGI代码来处理基于网页的输入。
如果我们把“raw_input()
”和“print
”结合到我们的类中,那么如果我们需要或想要支持其他形式的输入或输出,就会变得更加复杂。
如果我们创建一个只关注要收集数据的类,那么它可以为任何其他输入类提供一个接口,以获取提示列表,并引用“setter
”函数(也许还有一个“必填”或“可选”标志)。然后,任何输入类的实例都可以请求任何表单所需的输入列表……展示提示,调用“setter
”方法(返回一个布尔值,表示提供的数据是否有效),对“必填”字段的错误输入进行循环处理,提供跳过“可选”字段的选项,等等。
注意,显示提示、接受响应、通过它们的setter方法将这些响应传回数据对象,以及处理无效输入的逻辑,对于许多类型的表单都是相同的。我们只需要一种方式,让表单提供提示列表及其对应的验证函数(并确保所有这些验证函数具有相同的语义——接受相同的参数等等)。
下面是一个将输入行为与数据字段的存储和验证分开的例子:
#!/usr/bin/env python
class generic_form:
def __init__(self, element_list):
self.hints = list()
for each in element_list:
self.hints.append((each, each, self.store))
self.contents= dict()
def store(self, key, data):
'''Called by client instances
'''
self.contents[key] = data
return True
def get_hints(self):
return self.hints
def get(self, item):
return self.contents[item]
def form_input(form):
for each, key, fn in form.get_hints():
while True:
if fn(key,raw_input(each)):
break
else:
keep_trying = raw_input("Try again:")
if keep_trying.lower() in ['n', 'no', 'naw']:
break
if __name__ == '__main__':
sample_fields = ("Given Name: ",
"Surname: ",
"Date of Birth: ",
"etc: ")
example = generic_form(sample_fields)
print "Fill in my form:"
form_input(example)
print
print "Please review your input:"
for i, x, x in example.get_hints():
print example.get(i),
在这个例子中,额外的复杂性并没有做任何有用的事情。我们的generic_form没有进行任何验证。然而,这个输入函数可以与任何提供相同接口的数据/表单类一起使用。在这个例子中,这个接口只需要一个get_hints()
方法,提供“提示字符串”、存储键和存储函数引用的元组,以及一个store()
方法,必须返回“True”或“False”,并接受要存储的键和数据作为参数。
我们的存储键作为一个不透明的项传递给输入“客户端”,必须通过调用store()
方法传回,这一点有点微妙;但它允许我们对多个表单元素使用同一个验证函数……所有名称可以是任何字符串,所有日期必须通过某个time.strftime()
调用或某个第三方解析器……等等。
主要的观点是,我可以创建更好的表单类,实施适合收集和存储的数据的验证方法。输入示例适用于我们最初的简单表单,但对于返回有意义结果的表单,效果会更好(表单和输入处理之间更好的接口可能会提供“错误”和“帮助”提示,以及我们在这里展示的简单短“输入”提示。一个更复杂的系统可能会通过get_hints()
方法传递“datum”对象。这将要求表单类实例化这样的对象,并存储它们的列表,而不是我在这里展示的元组)。
另一个好处是,我还可以编写其他输入函数(或实现这些函数的类),也可以使用这个相同的接口与任何表单。因此,我可以编写一些HTML渲染和CGI处理,这样可以使用所有已经开发的表单,而无需更改我的数据验证语义。
(在这个例子中,我使用get_hints()
方法作为我粗略输出函数和输入的提示。我这样做只是为了保持例子的简单。在实际应用中,我希望将输入提示与输出处理分开。)