Wie kann ich eine beliebige Python-Quelldatei (deren Dateiname beliebige Zeichen enthalten kann und nicht immer mit endet .py
) in Python 3.3+ importieren ?
Ich habe imp.load_module
wie folgt verwendet:
>>> 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'>
Es funktioniert immer noch in Python 3.3, ist aber laut imp.load_module
Dokumentation veraltet:
Veraltet seit Version 3.3 : Nicht erforderlich, da Loader zum Laden von Modulen verwendet werden sollten und find_module () veraltet ist.
In der imp
Moduldokumentation wird empfohlen, Folgendes zu verwenden importlib
:
Hinweis Neue Programme sollten importlib anstelle dieses Moduls verwenden.
Was ist der richtige Weg, um eine beliebige Python-Quelldatei in Python 3.3+ zu laden, ohne die veraltete imp.load_module
Funktion zu verwenden?
python
python-3.x
python-3.3
falsetru
quelle
quelle
imp.load_module()
über eine direkte Importanweisung verwendet werden. Erwarten Sie, das Modul später nach Namen zu importieren (z. B.import a_b
)? Interessiert es Sie, dass bei diesem Ansatz keine benutzerdefinierten Importeure verwendet werden? Erwarten Sie, dass das Modul über alle Funktionen verfügt (z. B. definieren__name__
und__loader__
)?THIS='blah'
wie Zeilen). Der Name der Datei wird nicht mit beendet.py
. Mein Programm hat diese Datei gelesen.Antworten:
Ich habe eine Lösung aus dem
importlib
Testcode gefunden .Verwenden von 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'>
HINWEIS : Funktioniert nur in Python 3.3+ .
UPDATE
Loader.load_module
ist seit Python 3.4 veraltet. Verwenden SieLoader.exec_module
stattdessen:>>> 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'>
quelle
load_module
die via ignoriertwarnings.catch_warnings
. Wenn Sie stattdessen verwendenmod = imp.load_source('a_b', '/tmp/a-b.txt')
, wird die folgende Warnung (Verwendung-Wall
) ausgegeben :DeprecationWarning: imp.load_source() is deprecated; use importlib.machinery.SourceFileLoader(name, pathname).load_module() instead
.Kürzere Version der Lösung von @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'>
Ich habe es mit Python 3.5 und 3.6 getestet.
Laut den Kommentaren funktioniert es nicht mit beliebigen Dateierweiterungen.
quelle
importlib.util.spec_from_file_location(..)
kehrtNone
für mich zurück; Auslösen einer Ausnahme für den folgendenimportlib.util.module_from_spec(..)
Aufruf. (Siehe i.imgur.com/ZjyFhif.png )importlib.util.spec_from_file_location
Arbeiten für bekannte Dateinamenerweiterungen (.py
,.so
, ..), aber nicht für andere (.txt
...)Ähnlich wie @falsetru, jedoch für Python 3.5+ und unter Berücksichtigung der Angaben im
importlib
Dokument zur Verwendung vonimportlib.util.module_from_spec
overtypes.ModuleType
:Wir können jede Datei
importlib
alleine importieren, indem wir dieimportlib.machinery.SOURCE_SUFFIXES
Liste ändern .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()
quelle
importlib.machinery.EXTENSION_SUFFIXES.append('')
noch machtimportlib.util.spec_from_file_location
keine Rückkehr.importlib.util.spec_from_file_location
sollte immer noch mit Erweiterungen funktionieren, wenn Sie einen Lader angebenimportlib
HilfsfunktionHier ist ein praktischer, gebrauchsfertiger Helfer, der durch
imp
ein Beispiel ersetzt werden kann. Die Technik ist die gleiche wie bei https://stackoverflow.com/a/19011259/895245 . Dies bietet lediglich eine bequemere Funktion.main.py.
#!/usr/bin/env python3 import os import importlib def import_path(path): module_name = os.path.basename(path).replace('-', '_') spec = importlib.util.spec_from_loader( module_name, importlib.machinery.SourceFileLoader(module_name, path) ) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) sys.modules[module_name] = module return module notmain = import_path('not-main') print(notmain) print(notmain.x)
nicht-main
x = 1
Lauf:
Ausgabe:
<module 'not_main' from 'not-main'> 1
Ich ersetze
-
durch,_
weil meine importierbaren ausführbaren Python-Dateien ohne Erweiterung Bindestriche haben. Dies ist nicht obligatorisch, führt jedoch zu besseren Modulnamen.Dieses Muster wird auch in den Dokumenten unter https://docs.python.org/3.7/library/importlib.html#importing-a-source-file-directly erwähnt
Am Ende bin ich dazu übergegangen, weil nach dem Update auf Python 3.7 Folgendes
import imp
gedruckt wird:DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
und ich weiß nicht, wie ich das ausschalten soll, das wurde gefragt bei:
Getestet in Python 3.7.3.
quelle