1

我一直在尝试在 Python 中进行一些文本操作,但遇到了很多问题,主要是由于对 Python 中文件操作的工作原理存在根本性的误解,所以我希望能够澄清这一点。

因此,假设我正在遍历一个名为“my.txt”的文本文件,它具有以下内容:

3 10 7 8     
2 9 8 3  
4 1 4 2

我用来遍历文件的代码是:

file = open ("my.txt", 'r')
for line in file:
    print line`

我从教程中复制并粘贴了上面的代码。我知道它做了什么,但我不知道它为什么会起作用,这让我很困扰。我试图准确理解变量“line”在文件中代表什么。它是数据类型(字符串?)还是其他东西。我的直觉告诉我,每一行都代表一个字符串,然后可以对其进行操作(这是我想要的),但我也明白字符串在 Python 中是不可变的。

内存在这一切中扮演什么角色,如果我的文件太大而无法放入内存,它还能工作吗?line[3] 是否允许我访问每行中的第四个元素?如果我只想在第二行工作,我可以这样做:

if line == 2: 

在for循环内?

值得注意的是,我对 Python 很陌生,并且来自 C\C++ 背景(不习惯于不可变字符串)。我知道我将很多问题挤成一个问题,但是对一般主题的任何澄清都会很有帮助:)

4

5 回答 5

3

line是一行文本,表示为字符串。字符串是不可变的,但这不是操作它们的问题;Python 中的所有变量都是引用,分配给变量会将引用指向新对象。(在 C++ 中,您不能更改参考点的位置。)对文件的迭代会在行上进行迭代,因此在每次迭代时,都会line引用一个表示输入文件下一行的新字符串。

如果您熟悉基于范围的 for 循环或其他语言的 for-each 结构,那么这就是 Python 的for工作方式。循环变量不是计数器;你不能做

if line == 2:

因为line不是该行的索引;这是线本身。你可以做

for i, line in enumerate(f):
    if i == 2:
        do_stuff_with(line)
        break  # No need to load the rest of the file

请注意,这file是一个内置函数的名称,因此将该名称用于您自己的变量是个坏主意。

于 2013-08-20T19:45:20.983 回答
1

在 Python 中,您可以直接遍历文件。最好的方法是使用with声明,如:

with open("myfile.txt") as f:
    for i in f:
        # do stuff to each line in the file

这些行是代表文件中每一行(由换行符分隔)的字符串。如果你只想在第二行操作,你可以这样做:

with open("myfile.txt") as f:
    list_of_file = list(f)
    second_line = list_of_file[2]

如果您想访问第二行的一部分,可以按空格将其拆分为另一个列表,如下所示:

second_number_in_second_line = second_line.split()[1]

关于内存,直接遍历文件并不会将其全部读入内存,但是将其变成alist可以。如果您想在不这样做的情况下访问各个行,请使用itertools.islice.

于 2013-08-20T19:37:53.847 回答
1

在每次迭代中,line变量都填充了从文件中读取的后续行的内容。因此,您将拥有:

第一次迭代中的“3 10 7 8”第二次迭代
中的“2 9 8 3”
等。

要单独获取数字,请使用 split 方法:link

所以比较line2没有意义的。如果要识别行号,可以尝试:

lineNumber = 0
for line in file:
  print line
  if lineNumber == 2:
    print "that was the second line!"
  lineNumber += 1

正如评论中所建议的,您可以通过使用enumerate来简化它:

for lineNumber, line in enumerate(file):
  print line
    if lineNumber == 2:
      print "that was the second line!"
于 2013-08-20T19:39:41.247 回答
1

假设您有相同的文件:

3 10 7 8\n     
2 9 8 3\n  
4 1 4 2\n

有许多对文件对象进行操作的文件方法

在 Python 中,您可以逐字符读取文件,C 风格:

with open('/tmp/test.txt', 'r') as fin:     # fin is a 'file object' 
    while True:
        ch=fin.read(1)
        if not ch:
            break
        print ch,                           # comma suppresses the CR

您可以将整个文件作为单个字符串读取:

with open('/tmp/test.txt', 'r') as fin:
    data=fin.read()
    print data    

作为枚举行:

with open('/tmp/test.txt', 'r') as fin:
    for i, line in enumerate(fin):
        print i, line    

作为字符串列表:

with open('/tmp/test.txt', 'r') as fin:
    data=fin.readlines()  

循环文件对象的习惯用法:

for line in fin:                 # 'fin' is a file object result of open
    print line

是同义词:

for line in fin.readline():
    print line

类似于:

for line in 'line 1\nline 2\nline 3'.splitlines():
    print line

一旦您习惯了循环某事物元素的 Python 样式循环(或 Perl、Obj C 或 Java 范围样式循环),您就可以不加思索地使用它们。

如果你想要每个项目的索引 - 使用enumerate

于 2013-08-20T20:31:07.083 回答
0

您可以使用您显示的代码迭代任何大小的文件,并且它不应消耗超出最长单行大小的任何大量内存。

至于它是如何工作的,您可以深入研究 Python 本身的源代码以了解其中的血腥细节。在更高的层次上,只需考虑文件对象的实现者,在 Python 中,选择实现逐行迭代作为其类的一个特性。

Python 中的许多集合数据类型和 I/O 接口都实现了某种形式的迭代。因此,for构造是 Python 中最常见的循环类型。您可以迭代列表、元组和集合(按项目)、字符串(按字符)、字典(按键),并且许多类(包括标准库中的类以及来自第三方的类)实现“迭代器 (编码)协议”来促进这种使用。

于 2013-08-20T20:19:40.873 回答