0

我有一个 txt 文件,其中包含如下列表形式的内容:

[1,2,3,4]
[5,6,7,8]

我使用以下代码将这些列表放入列表中:

t = open('filename.txt', 'r+w')
contents = t.readlines()

alist = []

for i in contents:
    alist.append(i)

当我跑

alist[0]

我明白了

[1,2,3,4]

但是当我跑步时

for a in alist:
    print a[0]

我明白了

[

而不是列表中的第一个值。

4

3 回答 3

4

.readlines()将行读取为字符串。该字符串的第一个字符是[.

如果要读取文本文件并将其“反序列化”为数据结构,最简单的方法是使用 Python 的内置eval()函数。更安全的方法是使用ast.literal_eval().

http://docs.python.org/2/library/ast.html?highlight=literal#ast.literal_eval

建议代码:

import ast

with open("filename.txt") as f:
    alist = [ast.literal_eval(line) for line in f]

print(type(alist[0]))  # prints: <type 'list'>
print(alist[0]) # prints: [1,2,3,4]

我们几乎从不想打电话.readlines();它会占用文件中的所有行,因此如果文件非常大,则会导致程序的内存使用量大幅增加。一个打开的文件句柄对象(在我的示例中,f)可以用作迭代器,每次迭代它都会从文件中产生一行。因此,for循环或列表推导将从文件中一次拉出一行。因此,这个示例程序不会将整个文件保存在内存中;在构建列表时,它一次只保留一行。如果这个程序调用.readlines()它会保留所有的行和列表,所以峰值内存使用会更高。(当然,对于像这个例子这样小的输入文件来说,这并不重要。但是用内存高效的方式做事情很容易,为什么不呢?)

with使用打开文件始终是一种好习惯。然后你知道文件将在你完成后正确关闭。

我们使用列表推导来构建 的结果列表,ast.literal_eval()对于给定的输入文件,它每行返回一个列表,因此alist将是一个列表列表。

于 2013-03-05T20:50:52.080 回答
3

如果您只是继承或下载了这些文件并且无法对格式做任何事情,并且您知道它们应该被视为 Pythonlist的行,ast.literal_eval那么这是最好的答案,正如 steveha 解释的那样:

t = open('filename.txt', 'r')
alist = []    
for i in contents:
    alist.append(ast.literal_eval(i))

如果您继承或下载了这些文件,并且只是猜测格式,那么它们实际上可能打算被读取为 JSON 行,因为它们绝对是有效的 JSON,就像它们是有效的 Python 文字一样。在这种情况下:

t = open('filename.txt', 'r')
alist = []    
for i in contents:
    alist.append(json.loads(i))

但是,如果您是首先创建这些文件的人,那么您应该以专为序列化设计的方式创建它们。

例如,而不是这个:

t = open('filename.txt', 'w')
for i in alist:
    print >>t, i

做这样的事情:

t = open('filename.txt', 'w')
json.dump(alist, t)

然后你可以这样写你的阅读代码:

t = open('filename.txt', 'r')
alist = json.load(t)

JSON、YAML 或 Pickle 等序列化格式的全部意义在于,它们是专门设计的,以便您可以写入一个值,然后再读回相同的值。

print,str等函数不是为此而设计的;它们的设计使您可以以最好的人类可读形式显示一个值,即使以后很难或不可能读回。

该功能repr介于两者之间。它的设计目的是让玩交互式提示的人可读,因此如果可能的话,它会为您提供一个字符串,您可以在提示中键入该字符串以获取相同的值。这意味着,在某些情况下,ast.literal_eval是 的倒数repr,就像json.load的倒数一样json.dump。但是你不应该依赖这个,即使在处理它工作的类型时也是如此。


关于您的代码的一些附注:

t = open('filename.txt', 'r+w')

如果您只是要读取文件,请不要尝试打开它进行写入。此外,如果您确实想同时打开读取和写入,则正确的模式字符串是r+,而不是r+w。(你这样做的方式在技术上是一个错误,但大多数 Python 版本都会忽略w,所以你可以侥幸逃脱。)

如果模式是r,则根本不需要指定它,因为这是默认设置。

同时,你永远不会close文件。最简单的方法是使用with语句。

contents = t.readlines()

几乎从来没有一个很好的理由打电话readlines()。这为您提供了一系列行 - 但文件本身已经是一系列行。你所做的只是制作一个额外的副本。

alist = []

for i in contents:
    alist.append(i)

这种模式——创建一个空列表,然后在循环中附加到它——是如此普遍,以至于 Python 有一个快捷方式,称为列表推导。与显式循环相比,理解更简洁、更易读、更难出错、速度更快,因此大部分时间都值得使用它们。

最后,最好给变量起有意义的名称。特别是如果您希望其他人(或您自己,六个月后)能够调试您的代码。如果它工作得很好,我们可以通过它们的作用来判断变量的含义——但如果不是,我们就无法修复它,除非我们能猜出它们应该是什么意思,而名称是表明这一点的最佳方式。

所以,把它们放在一起,你的原始代码可以写成:

with open('filename.txt') as textfile:
    alist = [line for line in textfile]

各种固定版本是:

with open('filename.txt') as textfile:
    alist = [ast.literal_eval(line) for line in textfile]

with open('filename.txt') as textfile:
    alist = [json.loads(line) for line in textfile]

with open('filename.txt') as textfile:
    alist = json.load(textfile)
于 2013-03-05T21:14:06.417 回答
0

你所拥有的是一个字符串列表。一个带有括号和逗号的字符串并不是一个神奇的列表,它只是一个带有括号和逗号的字符串。

alist是列表。在您的循环中,a是该列表中的一个项目:首先,它是alist[0],然后alist[1]依此类推。因此,a[0]要求alist[0][0],alist[1][0]等:每行的第一个字符。这就是你得到的。

如果要将其转换为实际的 Python 列表,请使用ast.literal_eval().

于 2013-03-05T20:58:19.577 回答