Python:如何正确使用readline()和readlines()函数

3
我编写了一个Python脚本,使用普林斯顿英语Wordnet的数据和 Gödel, Escher, Bach提供的图表随机创建句子。调用python GEB.py会产生一系列毫无意义的英文句子,例如:

resurgent inaesthetic cost. the bryophytic fingernail. aversive fortieth peach. the asterismal hide. the flour who translate gown which take_a_dare a punch through applewood whom the renewed request enfeoff. an lobeliaceous freighter beside tuna.

并将它们保存到gibberish.txt中。这个脚本运行得很好。
另一个脚本(translator.py)通过py-googletrans Python模块尝试将那些随机的句子翻译成葡萄牙语。
from googletrans import Translator
import json

tradutor = Translator()

with open('data.json') as dataFile:
    data = json.load(dataFile)


def buscaLocal(keyword):
    if keyword in data:
        print(keyword + data[keyword])
    else:
        buscaAPI(keyword)


def buscaAPI(keyword):
    result = tradutor.translate(keyword, dest="pt")
    data.update({keyword: result.text})

    with open('data.json', 'w') as fp:
        json.dump(data, fp)

    print(keyword + result.text)


keyword = open('/home/user/gibberish.txt', 'r').readline()
buscaLocal(keyword)

目前第二个脚本只输出 gibberish.txt 中第一句话的乱码翻译,类似于:
复苏的不美观成本。 aumento de custos inestético.
我尝试使用 readlines() 而不是 readline(),但是我遇到了以下错误:
Traceback (most recent call last):
  File "main.py", line 28, in <module>
    buscaLocal(keyword)
  File "main.py", line 11, in buscaLocal
    if keyword in data:
TypeError: unhashable type: 'list'

我已经阅读了关于这个错误的类似问题,但是我不清楚应该使用什么来读取包含在gibberish.txt中的整个句子列表(新句子在新行开头)。
如何读取包含在gibberish.txt中的整个句子列表? 我应该如何修改translator.py中的代码才能实现这一点? 如果必要的话,我可以编辑问题,我是一个Python新手,如果有人能帮助我,我会非常感激。

2
请提供完整的错误消息,包括堆栈跟踪。我怀疑是 readlines 导致了这个错误。相反,readlines 返回一个行的列表,您可能正在尝试将该列表放入一个 dict 中,但是您不能这样做,因为列表对象不可哈希。一般来说,您需要提供一个 [mcve]。 - juanpa.arrivillaga
1
特别是在这里:data.update({keyword: result.text}) - juanpa.arrivillaga
刚刚编辑了完整的错误信息,抱歉。 - reaction hashs
好的,就像我解释的那样,readlines 返回一个 list 对象,它不可哈希,因此不能用作 dict 对象的键。 - juanpa.arrivillaga
我明白了,所以readlines()在这里完全不适用?感谢您的帮助。因此,在代码片段中提供的readline()输出句子列表中第一行的翻译。那么,我应该使用什么来输出.txt文件中所有句子的翻译呢? - reaction hashs
readlines 肯定可行,或者你可以直接遍历文件迭代器。参见@arryph的答案。 - juanpa.arrivillaga
3个回答

11

首先,让我们看看你对文件对象所做的操作。你打开一个文件,获取一行内容,然后不关闭它。更好的方法是处理整个文件,然后再关闭它。通常使用with块来完成这个任务,即使发生错误,它也会关闭文件:

with open('gibberish.txt') as f:
    # do stuff to f

除了物质利益外,这样做还会使界面更清晰,因为f不再是一个丢弃的对象。您有三个简单的选项来处理整个文件:

  1. Use readline in a loop since it will only read one line at a time. You will have to strip off the newline characters manually and terminate the loop when '' appears:

    while True:
        line = f.readline()
        if not line: break
        keyword = line.rstrip()
        buscaLocal(keyword)
    

    This loop can take many forms, one of which is shown here.

  2. Use readlines to read in all the lines in the file at once into a list of strings:

    for line in f.readlines():
        keyword = line.rstrip()
        buscaLocal(keyword)
    

    This is much cleaner than the previous option, since you don't need to check for loop termination manually, but it has the disadvantage of loading the entire file all at once, which the readline loop does not.

    This brings us to the third option.

  3. Python files are iterable objects. You can have the cleanliness of the readlines approach with the memory savings of readline:

    for line in f:
         buscaLocal(line.rstrip())
    

    this approach can be simulated using readline with the more arcane form of next to create a similar iterator:

    for line in next(f.readline, ''):
         buscaLocal(line.rstrip())
    

作为一个附带说明,我会对你的函数进行一些修改:

def buscaLocal(keyword):
    if keyword not in data:
        buscaAPI(keyword)
    print(keyword + data[keyword])

def buscaAPI(keyword):
    # Make your function do one thing. In this case, do a lookup.
    # Printing is not the task for this function.
    result = tradutor.translate(keyword, dest="pt")
    # No need to do a complicated update with a whole new
    # dict object when you can do a simple assignment.
    data[keyword] = result.text

...

# Avoid rewriting the file every time you get a new word.
# Do it once at the very end.
with open('data.json', 'w') as fp:
    json.dump(data, fp)

哇,这是一堂很棒的课程。对于像我这样的初学者来说,这里有很多东西可以学习。我稍后会尝试这些方法,以使程序更加高效,并回到您这里。感谢您抽出时间写下如此详细的答案,真的非常感激。 - reaction hashs
@Mad Physicist,如果我没有看过您的帖子,我就不会知道我可以通过引用文件指针迭代行!而这种类型(或类)是“_io.TextIOWrapper”!太棒了! - Sherman Chen
@ShermanChen。很高兴你从我的帖子中获得了有用的东西。只是作为一个提示,如果你以二进制模式打开文件,类型会不同。 - Mad Physicist
@疯狂物理学家,哦。我尝试读取一个二进制文件,它的类型是 '_io.BufferedReader'。 - Sherman Chen

2
如果您正在使用readline()函数,则需要记住该函数仅返回一行,因此您需要使用循环来遍历文本文件中的所有行。如果使用readlines(),则该函数会一次读取整个文件,但会将每个行作为列表返回。列表数据类型是不可哈希的,不能用作dict对象中的键,这就是为什么if keyword in data:行会发出错误,因为keyword在此处是所有行的列表。一个简单的for循环可以解决这个问题。
text_lines = open('/home/user/gibberish.txt', 'r').readlines()
for line in text_lines:
     buscaLocal(line)

此循环将遍历列表中的所有行,访问字典时可能会出错,因为键元素将是一个字符串。


谢谢 @arryph,非常好用。对于问这么基本的问题,我很抱歉,有时候我们会被最原始的问题困扰。感谢你的帮助! - reaction hashs

0

或者直接使用海象运算符:

while line := f.readline():
    # ... some code
    print(line)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接