未翻訳のページ
このページはまだ日本語に翻訳されていないため、英語の原文を表示しています。 翻訳に協力する
mimetypes Module Complexity¶
The mimetypes module maps filename extensions to MIME types and back. Its database is a few
dictionaries: guessing a type splits the extension off the name and looks it up, so the cost
follows the name you pass in, not the size of the database. The expensive work happens once, when
the database is built from the built-in tables and the system's mime.types files.
p is the characters in the path or URL passed in, e is the extensions registered for one MIME
type, b is the entries in the built-in tables (fixed per release, a couple of hundred), f is the
characters in the mime.types files read, and r, on Windows, is the keys under
HKEY_CLASSES_ROOT. A MIME type or a single extension is treated as short: hashing, lowering and
comparing one is O(1), and suffix_map entries do not chain, as the built-in ones do not. Reading a
file prices each registration at O(1), since a real type has a handful of extensions; add_type()
shows the O(e) scan behind it.
Complexity Reference¶
Module functions¶
| Operation | Time | Space | Notes |
|---|---|---|---|
mimetypes.guess_type(url, strict=True) |
O(p) | O(p) | Parses url as a URL, then splits off its extensions; the first module-level guess or add_type() runs init() |
mimetypes.guess_file_type(path, *, strict=True) |
O(p) | O(p) | Python 3.13+; a path, not a URL |
mimetypes.guess_all_extensions(type, strict=True) |
O(e) | O(e) | Returns a new list; strict=False merges the non-standard list by membership scans, O(e²) |
mimetypes.guess_extension(type, strict=True) |
O(e) | O(e) | The first entry of guess_all_extensions(), which it builds in full; O(e²) with strict=False |
mimetypes.add_type(type, ext, strict=True) |
O(e) | O(1) | Scans the type's extension list before appending; a known extension is re-pointed to the new type |
mimetypes.init(files=None) |
O(b + f) | O(b + f) | Builds a new database from the built-in tables, every knownfiles entry that exists and files, dropping earlier add_type() calls; with files given once a database exists, reads only those files into it, O(f). On Windows it also reads the registry, O(r) |
mimetypes.read_mime_types(filename) |
O(b + f) | O(b + f) | Parses into a throwaway MimeTypes, so the result holds the built-in types as well as the file's; nothing is registered in the module database, and an unreadable file returns None |
Module data¶
| Operation | Time | Space | Notes |
|---|---|---|---|
mimetypes.inited |
O(1) | O(1) | True once init() has run |
mimetypes.knownfiles |
O(1) | O(1) | The mime.types paths init() tries; a missing one is skipped |
mimetypes.types_map, mimetypes.common_types |
O(1) | O(1) | Extension to type, strict and non-standard; after init(), the module database's own dicts, so an edit changes later guesses |
mimetypes.encodings_map, mimetypes.suffix_map |
O(1) | O(1) | Extension to encoding (.gz to gzip), and extension to extensions (.tgz to .tar.gz); the same live dicts after init() |
MimeTypes¶
| Operation | Time | Space | Notes |
|---|---|---|---|
mimetypes.MimeTypes(filenames=(), strict=True) |
O(b + f) | O(b + f) | Copies the built-in tables, not the module database, then reads filenames; runs init() first if the module has not |
MimeTypes.guess_type(url, strict=True), MimeTypes.guess_file_type(path, *, strict=True) |
O(p) | O(p) | As the module functions, on this instance's tables; guess_file_type is Python 3.13+ |
MimeTypes.guess_all_extensions(type, strict=True), MimeTypes.guess_extension(type, strict=True) |
O(e) | O(e) | As the module functions; O(e²) with strict=False |
MimeTypes.add_type(type, ext, strict=True) |
O(e) | O(1) | As the module function |
MimeTypes.read(filename, strict=True), MimeTypes.readfp(fp, strict=True) |
O(f) | O(f) | A line at a time |
MimeTypes.read_windows_registry(strict=True) |
O(r) | O(r) | Windows; returns at once on other platforms |
MimeTypes.types_map, MimeTypes.types_map_inv |
O(1) | O(1) | Pairs of dicts, non-standard first and strict second; types_map_inv maps a type to its extension list |
MimeTypes.encodings_map, MimeTypes.suffix_map |
O(1) | O(1) | This instance's own copies |
Guessing a Type¶
A guess splits the extension off the name and looks it up, so it costs the length of the name and
never the size of the database. guess_type() takes a URL and parses it first; guess_file_type() takes a path.
Encoding suffixes such as .gz are peeled off before the type is looked up, and suffix_map
expands shorthands such as .tgz first.
import mimetypes
import sys
db = mimetypes.MimeTypes() # O(b) - the built-in tables; init() too on first use
assert db.guess_type('report.pdf') == ('application/pdf', None) # O(p)
assert db.guess_type('https://example.com/img/logo.png') == ('image/png', None)
assert db.guess_type('backup.tar.gz') == ('application/x-tar', 'gzip')
assert db.guess_type('backup.tgz') == ('application/x-tar', 'gzip') # via suffix_map
assert db.guess_type('README') == (None, None)
# A data: URL carries its own type
assert db.guess_type('data:text/csv;base64,YSxi') == ('text/csv', None)
# The query string is not part of the extension
assert db.guess_type('https://example.com/logo.png?v=2') == ('image/png', None)
if sys.version_info >= (3, 13):
assert db.guess_file_type('/srv/files/report.pdf') == ('application/pdf', None) # O(p)
From a Type to Extensions¶
The reverse direction looks the type up in types_map_inv and copies its extension list, so
guess_extension() costs the whole list even though it returns one entry. Strict extensions come
before non-standard ones, and within each the first one registered wins.
import mimetypes
db = mimetypes.MimeTypes()
extensions = db.guess_all_extensions('image/jpeg') # O(e)
assert extensions[0] == db.guess_extension('image/jpeg') # O(e)
assert '.jpeg' in extensions and '.jpg' in extensions
assert db.guess_extension('application/x-unknown') is None
The Module Database¶
The module functions share one database, built on first use by init(). Building it costs the
built-in tables plus every mime.types file in knownfiles that exists, so the first guess in a
process pays for all of it and later guesses do not. Calling init() again rebuilds it from
scratch, which drops anything registered with add_type().
import mimetypes
mimetypes.add_type('application/x-pydemo', '.pydemo') # O(e); builds the database first if needed
assert mimetypes.inited
assert mimetypes.guess_type('file.pydemo') == ('application/x-pydemo', None) # O(p)
assert mimetypes.guess_extension('application/x-pydemo') == '.pydemo' # O(e)
mimetypes.init() # O(b + f) - a new database
assert mimetypes.guess_type('file.pydemo') == (None, None)
Registering Types¶
add_type() makes an extension point at a type, replacing whatever it pointed at, and appends the
extension to the type's list unless it is already there. strict=False puts the mapping in the
non-standard table, which a guess consults only when asked to.
import mimetypes
db = mimetypes.MimeTypes()
db.add_type('application/x-notes', '.notes', strict=False) # O(e)
assert db.guess_type('a.notes') == (None, None)
assert db.guess_type('a.notes', strict=False) == ('application/x-notes', None)
db.add_type('application/x-notes-v2', '.notes', strict=False) # re-points the extension
assert db.guess_type('a.notes', strict=False) == ('application/x-notes-v2', None)
Private Databases¶
A MimeTypes instance starts from the built-in tables, not from the module database, so it does
not see the system's mime.types files or anything add_type() put there. That makes its answers
the same on every machine running one Python release. Building one registers every built-in entry,
so build it once and keep it.
import io
import mimetypes
mimetypes.add_type('application/x-module-only', '.modonly')
db = mimetypes.MimeTypes() # O(b)
assert db.guess_type('a.modonly') == (None, None) # the module database is not copied
db.readfp(io.StringIO("# comment\napplication/x-custom cstm pycust\n")) # O(f)
assert db.guess_type('file.pycust') == ('application/x-custom', None)
assert db.guess_all_extensions('application/x-custom') == ['.cstm', '.pycust']
assert mimetypes.guess_type('file.pycust') == (None, None) # only this instance changed
Reading a mime.types File¶
read_mime_types() parses a file into a throwaway MimeTypes and returns its strict table, so the
dictionary it hands back includes the built-in types, and the file's types are not registered in the
module database.
import mimetypes
import os
import tempfile
with tempfile.NamedTemporaryFile('w', suffix='.types', delete=False) as handle:
handle.write("application/x-example pyexample\n")
try:
table = mimetypes.read_mime_types(handle.name) # O(b + f)
assert table['.pyexample'] == 'application/x-example'
assert table['.pdf'] == 'application/pdf' # the built-in types come along
assert mimetypes.guess_type('file.pyexample') == (None, None) # not registered
finally:
os.remove(handle.name)
assert mimetypes.read_mime_types(handle.name) is None # unreadable file
Common Patterns¶
A Content-Type Header¶
import mimetypes
def content_headers(filename):
mime_type, encoding = mimetypes.guess_type(filename) # O(p)
headers = {'Content-Type': mime_type or 'application/octet-stream'}
if encoding is not None:
headers['Content-Encoding'] = encoding
return headers
assert content_headers('index.html') == {'Content-Type': 'text/html'}
assert content_headers('dump.sql.gz')['Content-Encoding'] == 'gzip'
assert content_headers('noextension') == {'Content-Type': 'application/octet-stream'}
Performance Best Practices¶
✅ Do:
- Keep one
MimeTypesinstance, or use the module functions, rather than building a database per request: each build registers every built-in entry - Use
guess_file_type()for paths on Python 3.13+; it skips the URL parse - Use a
MimeTypesinstance when answers must not depend on the machine'smime.typesfiles
❌ Avoid:
- Calling
init()to "refresh" the database - it rebuilds it and drops everyadd_type() read_mime_types()to register a file's types - it returns a table and registers nothing; useinit([filename])orMimeTypes.read()- Registering thousands of extensions under one type; each
add_type()scans the type's list
Version Notes¶
- Python 3.11+:
guess_type()ignores a URL's query string and fragment; on 3.10 they stay in the name the extension is taken from and can change the result - Python 3.13+: Added
guess_file_type(); passing a path toguess_type()is soft deprecated - Python 3.14+:
add_type()with an extension not starting with.emitsDeprecationWarning - All Python 3: The module functions include the system's
mime.typesfiles, so their answers vary by machine; aMimeTypesinstance does not read them