importlib - Il Meccanismo di Importazione di Python

Scopo: Espone l'implementazione dell'istruzione import di Python

Il modulo importlib include funzioni che implementano il meccanismo di importazione di Python per il caricamento di codice in moduli e pacchetti. Costituisce un punto di accesso per importare dinamicamente i moduli, utile in taluni casi dove il nome del modulo che deve essere importato non è noto quando il codice viene scritto (ad esempio per plugin o estensioni a una applicazione).

Pacchetto di esempio

Gli esempi di questo articolo usano un pacchetto chiamato esempio con __init__.py.

# esempio/__init__.py

print('Importazione pacchetto di esempio')

Il pacchetto contiene anche submodule.py.

# esempio/submodule.py

print('Importazione di submodule')

Prestare attenzione al testo stampato dalle chiamate a print() quando il pacchetto o il modulo viene importato.

Tipi di Modulo

Python supporta parecchi stili di moduli, ognuno dei quali richiede il suo proprio modo di gestione quando viene aperto e aggiunto allo spazio dei nomi, e il supporto per i formati varia a seconda della piattaforma. Ad esempio, sotto Microsoft Windows, le librerie condivise sono caricate da file con estensioni .dll o .pyd, invece che .so. Anche le estensioni per i moduli C potrebbero cambiare quando si usa una compilazione per debug dell'interprete invece che una normale compilazione di rilascio, visto che possono anche essere compilati con informazioni di debug incluse. Se una estensione di libreria C o altro modulo non viene caricato nel modo atteso, si utilizzino le costanti definite in importlib.machinery per trovare i tipi supportati dalla piattaforma corrente, e i parametri per caricarle.

# importlib_suffixes.py

import importlib.machinery

SUFFIXES = [
    ('Sorgente:', importlib.machinery.SOURCE_SUFFIXES),
    ('Debug:',
     importlib.machinery.DEBUG_BYTECODE_SUFFIXES),
    ('Ottimizzato:',
     importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES),
    ('Bytecode:', importlib.machinery.BYTECODE_SUFFIXES),
    ('Estensione:', importlib.machinery.EXTENSION_SUFFIXES),
]


def main():
    tmpl = '{:<12}  {}'
    for name, value in SUFFIXES:
        print(tmpl.format(name, value))


if __name__ == '__main__':
    main()

Il valore ritornato è una sequenza di tuple che contengono l'estensione del file, la modalità usata per aprire il file contenente il modulo e un tipo codice da una costante definita nel modulo. Questa tabella è incompleta visto che alcuni dei tipi importabili di modulo o pacchetto non corrispondono a singoli file.

$ python3 importlib_suffixes.py

Sorgente:     ['.py']
Debug:        ['.pyc']
Ottimizzato:  ['.pyc']
Bytecode:     ['.pyc']
Estensione:   ['.cpython-38-x86_64-linux-gnu.so', '.abi3.so', '.so']

Importare Moduli

L'API di alto livello in importlib rende semplice importare un modulo dato un nome assoluto o relativo. Quando si usa un nome di modulo relativo, si specifichi il pacchetto che contiene il modulo come argomento separato.

# importlib_import_module.py

import importlib


m1 = importlib.import_module('esempio.submodule')
print(m1)

m2 = importlib.import_module('.submodule', package='esempio')
print(m2)

print(m1 is m2)

Il valore ritornato da import_module() è l'oggetto del modulo che era stato creato dall'importazione.

$ python3 importlib_import_module.py

Importazione pacchetto di esempio
Importazione di submodule
<module 'esempio.submodule' from '.../esempio/submodule.py'>
<module 'esempio.submodule' from '.../esempio/submodule.py'>
True

Se il modulo non può essere importato, import_module() solleva una eccezione ImportError.

# importlib_import_module_error.py

import importlib


try:
    importlib.import_module('esempio.nosuchmodule')
except ImportError as err:
    print('Errore:', err)

Il messaggio di errore include il nome del modulo mancante.

$ python3 importlib_import_module_error.py

Importazione pacchetto di esempio
Errore: No module named 'esempio.nosuchmodule'

Per ricaricare un modulo esistente, si usi reload().

# importlib_reload.py

import importlib


m1 = importlib.import_module('esempio.submodule')
print(m1)

m2 = importlib.reload(m1)
print(m1 is m2)

Il valore di ritorno da reload() è il nuovo modulo. A seconda del tipo di caricatore usato, potrebbe essere la stessa istanza del modulo.

$ python3 importlib_reload.py

Importazione pacchetto di esempio
Importazione di submodule
<module 'esempio.submodule' from '.../esempio/submodule.py'>
Importazione di submodule
True

Caricatori

L'API di alto livello in importlib fornisce l'accesso agli oggetti di caricamento, Per ottenere un caricatore per un modulo si usi find_loader(). Poi per recuperare il modulo si usi il metodo load_module().

# importlib_find_loader.py

import importlib

loader = importlib.find_loader('esempio')
print('Caricatore:', loader)

m = loader.load_module()
print('Modulo:', m)

Questo esempio carica il livello superiore del pacchetto esempio.

$ python3 importlib_find_loader.py

Caricatore: <_frozen_importlib_external.SourceFileLoader object at 0x7fe2aac50fd0>
Importazione pacchetto di esempio
Modulo: <module 'esempio' from '.../esempio/__init__.py'>

I sottomoduli all'interno dei pacchetti devono essere caricati separatamente usando il percorso dal pacchetto. Nell'esempio seguente, il pacchetto prima viene caricato, quindi il suo percorso viene passato a find_loader() per creare un caricatore in grado di caricare il sottomodulo.

# importlib_submodule.py

import importlib

pkg_loader = importlib.find_loader('esempio')
pkg = pkg_loader.load_module()

loader = importlib.find_loader('submodule', pkg.__path__)
print('Caricatore:', loader)

m = loader.load_module()
print('Modulo:', m)

Diversamente da import_module(), il nome del sottomodulo dovrebbe essere passato senza alcun prefisso di percorso relativo, visto che il caricatore sarà già limitato dal percorso del pacchetto.

$ python3 importlib_submodule.py

Importazione pacchetto di esempio
Caricatore: <_frozen_importlib_external.SourceFileLoader object at 0x7f893b8de1d0>
Importazione di submodule
Modulo: <module 'submodule' from '.../esempio/submodule.py'>

Vedere anche:

importlib
La documentazione della libreria standard per questo modulo.
Moduli e importazioni
Agganci per importazione, il percorso di ricerca del modulo e altri meccanismi correlati nel modulo sys (in corso di traduzione)
inspect
Carica programmaticamente informazioni da un modulo.
PEP 302
Nuovi agganci per l'importazione
PEP 369
Agganci dopo l'importazione
PEP 488
Eliminazione dei file PYO