每週一個 Python 模組 | linecache

yongxinz發表於2019-03-09

專欄地址:每週一個 Python 模組

從檔案或匯入的 Python 模組中檢索文字行,儲存結果快取,以便更高效地從同一檔案中讀取多行。

linecache 在處理 Python 原始檔時,該模組用於 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 開始。

import linecache
from linecache_data import *

filename = make_tempfile()

# Pick out the same line from source and cache.
# (Notice that linecache counts from 1)
print('SOURCE:')
print('{!r}'.format(lorem.split('\n')[4]))
print()
print('CACHE:')
print('{!r}'.format(linecache.getline(filename, 5)))

cleanup(filename)

# output
# SOURCE:
# 'fermentum id, nonummy a, nonummy sit amet, ligula. Curabitur'
#
# CACHE:
# 'fermentum id, nonummy a, nonummy sit amet, ligula. Curabitur\n'
複製程式碼

返回的每一行都包含一個尾隨換行符。

處理空行

返回值始終包含行尾的換行符,因此如果行為空,則返回值只是換行符。

import linecache
from linecache_data import *

filename = make_tempfile()

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

cleanup(filename)
複製程式碼

輸入檔案的第八行不包含文字。

錯誤處理

如果請求的行號超出檔案中有效行的範圍,則 getline() 返回空字串。

import linecache
from linecache_data import *

filename = make_tempfile()

# The cache always returns a string, and uses
# an empty string to indicate a line which does
# not exist.
not_there = linecache.getline(filename, 500)
print('NOT THERE: {!r} includes {} characters'.format(not_there, len(not_there)))    # NOT THERE: '' includes 0 characters

cleanup(filename)
複製程式碼

輸入檔案只有 15 行,因此請求行 500 就像嘗試讀取檔案末尾一樣。

從不存在的檔案讀取以相同的方式處理。

import linecache

# Errors are even hidden if linecache cannot find the file
no_such_file = linecache.getline(
    'this_file_does_not_exist.txt', 1,
)
print('NO FILE: {!r}'.format(no_such_file)) # NO FILE: ''
複製程式碼

當呼叫者嘗試讀取資料時,模組永遠不會引發異常。

閱讀 Python 原始檔

由於 linecache 在生成回溯時使用得非常多,因此其關鍵特性之一是能夠通過指定模組的基本名稱在匯入路徑中查詢 Python 源模組。

import linecache
import os

# Look for the linecache module, using
# the built in sys.path search.
module_line = linecache.getline('linecache.py', 3)
print('MODULE:')
print(repr(module_line))

# Look at the linecache module source directly.
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))

# output
# 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'
複製程式碼

如果命名模組在當前目錄中找不到具有該名稱的檔案,則 linecache 會搜尋 sys.path。這個例子是尋找的 linecache.py,由於當前目錄中沒有,因此會找到標準庫中的檔案。

原文連結:

https://pymotw.com/3/linecache/index.html

相關文章