Ei vielä käännetty
Tätä sivua ei ole vielä käännetty suomeksi, joten se näytetään englanniksi. Auta kääntämään
linecache Module Complexity¶
The linecache module returns single lines of Python source files by number, and is what
traceback and inspect use to show source. It reads a file whole the first time any line of it
is asked for, keeps every line in a module-level cache, and answers later calls from memory
without touching the file again.
n is the characters in one source file, f is the files in the cache, t is the lines held
across all of them, and p is the entries on sys.path. Cache lookups by file name and each
os.stat() call are priced at O(1). Source that comes from a module loader rather than a file
also costs whatever the loader's get_source() costs, which is not priced here.
Complexity Reference¶
Reading lines¶
| Operation | Time | Space | Notes |
|---|---|---|---|
linecache.getline(filename, lineno, module_globals=None), first call for a file |
O(p + n) | O(n) | Reads and keeps the whole file, whichever line is asked for; p applies only to a relative name not found as given, which is then searched for along sys.path |
linecache.getline(...) for a cached file |
O(1) | O(1) | No I/O and no os.stat(): a file changed on disk keeps returning its old lines until checkcache() |
linecache.getline(...) for a file it cannot find |
O(p) | O(1) | Returns ''; a miss is not cached, so every call repeats the search. Names such as '<string>' return '' in O(1) without one |
linecache.lazycache(filename, module_globals) |
O(1) | O(1) | Records the module loader's get_source; nothing is fetched until the first getline() for that name |
Cache management¶
| Operation | Time | Space | Notes |
|---|---|---|---|
linecache.checkcache() |
O(f) | O(f) | Snapshots the cache's keys, then one os.stat() per entry read from a file; drops an entry whose size or modification time changed or whose file is gone. Entries from lazycache() or a loader are never checked |
linecache.checkcache(filename) |
O(1) | O(1) | The same check for one entry |
linecache.clearcache() |
O(f + t) | O(1) | Drops every entry and frees every cached line; the next getline() for each file reads it again |
Reading Lines¶
The First Call Reads the Whole File¶
Asking for one line costs the whole file once, and after that any line of it is a list index. The cache does not notice a file changing or disappearing; it keeps answering from the copy it read.
import linecache
import os
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.py', delete=False) as handle:
handle.write(''.join(f'x{i} = {i}\n' for i in range(1, 1001)))
path = handle.name
try:
assert linecache.getline(path, 1) == 'x1 = 1\n' # O(n) - reads all 1,000 lines
assert linecache.getline(path, 1000) == 'x1000 = 1000\n' # O(1) - already cached
assert linecache.getline(path, 5000) == '' # O(1) - out of range, never raises
finally:
os.remove(path)
# The file is gone, but the cached copy still answers
assert linecache.getline(path, 500) == 'x500 = 500\n' # O(1)
linecache.checkcache(path) # O(1) - the stat fails, so the entry is dropped
assert linecache.getline(path, 500) == ''
Misses Are Not Cached¶
A name that resolves to nothing is looked for again on every call. For a relative name that means
one os.stat() per sys.path entry each time, so repeated lookups of a missing file cost O(p)
apiece rather than O(1).
import linecache
assert linecache.getline('no_such_module_here.py', 1) == '' # O(p) - searches sys.path
assert linecache.getline('no_such_module_here.py', 1) == '' # O(p) again - nothing cached
# '<string>' names source that never had a file; it is rejected without a search
assert linecache.getline('<string>', 1) == '' # O(1)
Source Without a File¶
lazycache() lets a module whose source comes from its loader - a zip import, a custom importer -
be read later without keeping its globals around. Registering reads nothing; the first getline()
calls get_source() once and caches the result like a file's lines.
import linecache
calls = []
class Loader:
def get_source(self, name):
calls.append(name)
return 'first = 1\nsecond = 2\n'
name = '/virtual/generated_module.py' # no such file on disk
module_globals = {'__name__': 'generated_module', '__loader__': Loader()}
assert linecache.lazycache(name, module_globals) is True # O(1)
assert calls == [] # nothing fetched yet
assert linecache.getline(name, 2) == 'second = 2\n' # get_source() runs now
assert linecache.getline(name, 1) == 'first = 1\n' # O(1) - cached
assert calls == ['generated_module']
# Already cached, so there is nothing left to register
assert linecache.lazycache(name, module_globals) is False
linecache.clearcache()
Keeping the Cache Fresh¶
checkcache() is the only thing that notices an edited file, and it does so by comparing the size
and modification time recorded when the file was read. Pass a file name to check one entry instead
of statting every file in the cache.
import linecache
import os
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.py', delete=False) as handle:
handle.write('value = 1\n')
path = handle.name
try:
assert linecache.getline(path, 1) == 'value = 1\n' # O(n) - read and cached
with open(path, 'w') as edited:
edited.write('value = 2 # edited\n')
assert linecache.getline(path, 1) == 'value = 1\n' # O(1) - stale copy
linecache.checkcache(path) # O(1) - size changed, entry dropped
assert linecache.getline(path, 1) == 'value = 2 # edited\n' # O(n) - read again
linecache.checkcache() # O(f) - one stat per cached file
linecache.clearcache() # O(f + t) - drops every entry and line
finally:
os.remove(path)
Common Patterns¶
Reading a Range of Lines¶
Several lines from one file cost one read, however many are taken.
import linecache
import os
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.py', delete=False) as handle:
handle.write(''.join(f'line {i}\n' for i in range(1, 101)))
path = handle.name
try:
# O(n) for the first line, O(1) for each after it
context = [linecache.getline(path, number) for number in range(40, 45)]
finally:
os.remove(path)
linecache.checkcache(path)
assert context == [f'line {i}\n' for i in range(40, 45)]
Performance Best Practices¶
✅ Do:
- Take many lines from the same file through
getline(): only the first call reads it - Call
checkcache(filename)for the file you care about rather thancheckcache(), which stats every cached file - Call
clearcache()when you are done with large files; the cache holds them whole until then - Use
lazycache()for loader-backed source, so nothing is fetched unless a line is asked for
❌ Avoid:
getline()for one line of a large file you will not read again - it reads and keeps the whole file; iterate the file withitertools.isliceinstead- Calling
getline()repeatedly for a name that does not resolve - each call repeats the O(p) search - Expecting
getline()to see a file's edits without acheckcache()in between
Version Notes¶
- Python 3.14+:
getline()reads a<frozen ...>module's source throughmodule_globals['__file__']; earlier versions return''for those names