web-dev-qa-db-fra.com

Importer un fichier source python arbitraire. (Python 3.3+))

Comment puis-je importer un fichier source arbitraire python (dont le nom de fichier peut contenir des caractères et ne se termine pas toujours par .py) Dans Python 3,3 + ?

J'ai utilisé imp.load_module comme suit:

>>> import imp
>>> path = '/tmp/a-b.txt'
>>> with open(path, 'U') as f:
...     mod = imp.load_module('a_b', f, path, ('.py', 'U', imp.PY_SOURCE))
...
>>> mod
<module 'a_b' from '/tmp/a-b.txt'>

Il fonctionne toujours en Python 3.3, mais selon la documentation de imp.load_module, Il est déconseillé:

Déconseillé depuis la version 3.3: Inutile car les chargeurs doivent être utilisés pour charger les modules et find_module () est déconseillé.

et la documentation du module imp recommande d'utiliser importlib:

Remarque Les nouveaux programmes devraient utiliser importlib plutôt que ce module.

Quelle est la bonne façon de charger un fichier source arbitraire python dans Python 3.3+ sans utiliser la fonction imp.load_module Déconseillée)?

53
falsetru

Trouvé une solution à partir de importlib code de test .

Utilisation de importlib.machinery.SourceFileLoader :

>>> import importlib.machinery
>>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt')
>>> mod = loader.load_module()
>>> mod
<module 'a_b' from '/tmp/a-b.txt'>

[~ # ~] note [~ # ~] : ne fonctionne que dans Python 3.3 +.

[~ # ~] mise à jour [~ # ~] Loader.load_module est déconseillé depuis Python 3.4. Utilisez Loader.exec_module à la place:

>>> import types
>>> import importlib.machinery
>>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt')
>>> mod = types.ModuleType(loader.name)
>>> loader.exec_module(mod)
>>> mod
<module 'a_b'>

>>> import importlib.machinery
>>> import importlib.util
>>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt')
>>> spec = importlib.util.spec_from_loader(loader.name, loader)
>>> mod = importlib.util.module_from_spec(spec)
>>> loader.exec_module(mod)
>>> mod
<module 'a_b' from '/tmp/a-b.txt'>
52
falsetru

Version plus courte de la solution de @falsetru:

>>> import importlib.util
>>> spec = importlib.util.spec_from_file_location('a_b', '/tmp/a-b.py')
>>> mod = importlib.util.module_from_spec(spec)
>>> spec.loader.exec_module(mod)
>>> mod
<module 'a_b' from '/tmp/a-b.txt'>

Je l'ai testé avec Python 3.5 et 3.6.

Selon les commentaires, cela ne fonctionne pas avec des extensions de fichiers arbitraires.

17
Stefan Scherfke

Similaire à @falsetru mais pour Python 3.5 + et en tenant compte de ce que le importlib doc indique sur l'utilisation de importlib.util.module_from_spec plus de types.ModuleType:

Cette fonction [importlib.util.module_from_spec] est préférable à l'utilisation de types.ModuleType pour créer un nouveau module selon les spécifications est utilisé pour définir autant d'attributs contrôlés par l'importation sur le module que possible.

Nous pouvons importer n'importe quel fichier avec importlib seul en modifiant le importlib.machinery.SOURCE_SUFFIXES liste.

import importlib

importlib.machinery.SOURCE_SUFFIXES.append('') # empty string to allow any file
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# if desired: importlib.machinery.SOURCE_SUFFIXES.pop()
7
awalllllll