7.6. linecache — 高效率文件读取

未匹配的标注

目的:从文件或者导入的 Python 模块中检索文本行,并保存结果的缓存,使得同一文本的多行读取效率更高。

在处理 Python 源文件时,linecache 模块通常用于 Python 标准库的其它部分。缓存实现了在内存中保存文件内容,并将其解析为单独的行。API 通过索引列表返回所需的行,相比反复读取文件,解析行然后找到所需的行节省了很多时间。当从同一文件中查找多行时特别有用,例如为错误报告生成回溯时。

检测数据

由 Lorem Ipsum 生成器生成的这个文件用作样本输入。

linecache_data.py

import os
import tempfile

lorem = '''Lorem ipsum dolor sit amet, consectetuer
adipiscing elit.  Vivamus eget elit. In posuere mi non
risus. Mauris id quam posuere lectus sollicitudin
varius. Praesent at mi. Nunc eu velit. Sed augue massa,
fermentum id, nonummy a, nonummy sit amet, ligula. Curabitur
eros pede, egestas at, ultricies ac, apellentesque eu,
tellus.

Sed sed odio sed mi luctus mollis. Integer et nulla ac augue
convallis accumsan. Ut felis. Donec lectus sapien, elementum
nec, condimentum ac, interdum non, tellus. Aenean viverra,
mauris vehicula semper porttitor, ipsum odio consectetuer
lorem, ac imperdiet eros odio a sapien. Nulla mauris tellus,
aliquam non, egestas a, nonummy et, erat. Vivamus sagittis
porttitor eros.'''

def make_tempfile():
    fd, temp_file_name = tempfile.mkstemp()
    os.close(fd)
    with open(temp_file_name, 'wt') as f:
        f.write(lorem)
    return temp_file_name

def cleanup(filename):
    os.unlink(filename)

读取具体行

linecache() 读取文件行时,行号从1开始,但是数组索引是从0开始,因此要记得区分。

linecache_getline.py

import linecache
from linecache_data import *

filename = make_tempfile()

# 从源文件和缓存中挑出相同行
# (注意,linecache 从1开始,数组从0开始)
print('SOURCE:')
print('{!r}'.format(lorem.split('\n')[4]))
print()
print('CACHE:')
print('{!r}'.format(linecache.getline(filename, 5)))

cleanup(filename)

返回的每行都包含一个换行符。

$ python3 linecache_getline.py

SOURCE:
'fermentum id, nonummy a, nonummy sit amet, ligula. Curabitur'

CACHE:
'fermentum id, nonummy a, nonummy sit amet, ligula. Curabitur\n'

处理空行

由于返回值总是包含换行符,因此如果是空行,返回值就是换行符。

linecache_empty_line.py

import linecache
from linecache_data import *

filename = make_tempfile()

# Blank lines include the newline
print('BLANK : {!r}'.format(linecache.getline(filename, 8)))

cleanup(filename)

文件第8行没有文本内容,因此返回值就是一个换行符。

$ python3 linecache_empty_line.py

BLANK : '\n'

错误处理

如果请求的行号超出了文件有效行范围,getline() 返回一个空的字符串。

linecache_out_of_range.py

import linecache
from linecache_data import *

filename = make_tempfile()

# 缓存总是返回一个字符串,返回一个空的字符串
# 预示这个行不存在。
not_there = linecache.getline(filename, 500)
print('NOT THERE: {!r} includes {} characters'.format(
    not_there, len(not_there)))

cleanup(filename)

原本的文件只有15行,所以请求第500行就相当于读取文件的末尾。

$ python3 linecache_out_of_range.py

NOT THERE: '' includes 0 characters

读取一个不存在的文件会被按照相同的方式处理。

linecache_missing_file.py

import linecache

# 即使如果 linecache 找不到这个文件,错误也会被隐藏
no_such_file = linecache.getline(
    'this_file_does_not_exist.txt', 1,
)
print('NO FILE: {!r}'.format(no_such_file))

当调用者尝试通过这个模块读取数据时永远不会引发错误。

$ python3 linecache_missing_file.py

NO FILE: ''

读取 Python 源文件

由于 linecache 在创建回溯时被大量使用,因此它的一个关键特性是能够通过指定模块的基本名称在导入路径中查找 Python 源模块。

linecache_path_search.py

import linecache
import os

# 在 sys.path 中查找 linecache 模块
module_line = linecache.getline('linecache.py', 3)
print('MODULE:')
print(repr(module_line))

# 直接查找模块源文件
file_src = linecache.__file__
if file_src.endswith('.pyc'):
    file_src = file_src[:-1]
print('\nFILE:')
with open(file_src, 'r') as f:
    file_line = f.readlines()[2]
print(repr(file_line))

如果在当前目录中找不到 linecache 的缓存代码,那么就会去 sys.path 中继续搜索。由于当前目录中没有示例中的 linecache.py 的副本,因此在标准库中的找到了。

$ python3 linecache_path_search.py

MODULE:
'This is intended to read lines from modules imported -- hence
if a filename\n'

FILE:
'This is intended to read lines from modules imported -- hence
if a filename\n'

推荐阅读

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/pymotw/linecach...

译文地址:https://learnku.com/docs/pymotw/linecach...

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~