Wie kann ich ein Python-Modul mit seinem vollständigen Pfad laden? Beachten Sie, dass sich die Datei an einer beliebigen Stelle im Dateisystem befinden kann, da es sich um eine Konfigurationsoption handelt.
Wie kann ich ein Python-Modul mit seinem vollständigen Pfad laden? Beachten Sie, dass sich die Datei an einer beliebigen Stelle im Dateisystem befinden kann, da es sich um eine Konfigurationsoption handelt.
Antworten:
Für Python 3.5+ verwenden Sie:
import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()
Verwenden Sie für Python 3.3 und 3.4:
from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()
(Obwohl dies in Python 3.4 veraltet ist.)
Für Python 2 verwenden Sie:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
Es gibt äquivalente Komfortfunktionen für kompilierte Python-Dateien und DLLs.
Siehe auch http://bugs.python.org/issue21436 .
__import__
.
imp.load_source
setzt nur den Wert des .__name__
zurückgegebenen Moduls. Das Laden wird nicht beeinflusst.
imp.load_source()
bestimmt den Schlüssel des neuen Eintrags, der im sys.modules
Wörterbuch erstellt wurde, sodass das erste Argument tatsächlich das Laden beeinflusst.
imp
Modul ist seit Version 3.4 veraltet: Für das imp
Paket steht die Verwerfung zugunsten von aus importlib
.
Das Hinzufügen eines Pfads zu sys.path (gegenüber der Verwendung von imp) hat den Vorteil, dass beim Importieren von mehr als einem Modul aus einem einzelnen Paket die Arbeit vereinfacht wird. Zum Beispiel:
import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')
from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
sys.path.append
verweisen wir auf eine einzelne Python-Datei anstelle eines Verzeichnisses?
importlib.import_module(mod_name)
kann hier anstelle des expliziten Imports verwendet werden, wenn der Modulname zur Laufzeit nicht bekannt ist. Am sys.path.pop()
Ende würde ich jedoch ein hinzufügen , vorausgesetzt, der importierte Code versucht nicht, mehr Module zu importieren, während er verwendet wird.
Wenn Ihr Top-Level-Modul keine Datei ist, sondern als Verzeichnis mit __init__.py gepackt ist, funktioniert die akzeptierte Lösung fast, aber nicht ganz. In Python 3.5+ wird der folgende Code benötigt (beachten Sie die hinzugefügte Zeile, die mit 'sys.modules' beginnt):
MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
Ohne diese Zeile wird bei der Ausführung von exec_module versucht, relative Importe in Ihrer obersten Ebene __init__.py an den Modulnamen der obersten Ebene zu binden - in diesem Fall "mymodule". "Mymodule" ist jedoch noch nicht geladen, sodass die Fehlermeldung "SystemError: Übergeordnetes Modul 'mymodule' nicht geladen, relativer Import kann nicht ausgeführt werden" angezeigt wird. Sie müssen den Namen also binden, bevor Sie ihn laden. Der Grund dafür ist die grundlegende Invariante des relativen Importsystems: "Die invariante Position ist, dass Sie sys.modules ['spam'] und sys.modules ['spam.foo'] haben (wie Sie es nach dem obigen Import tun würden ) muss letzteres als foo-Attribut des ersteren erscheinen " wie hier diskutiert .
mymodule
?
/path/to/your/module/
ist eigentlich /path/to/your/PACKAGE/
? und damit mymodule
meinst du myfile.py
?
Um Ihr Modul zu importieren, müssen Sie sein Verzeichnis vorübergehend oder dauerhaft zur Umgebungsvariablen hinzufügen.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Hinzufügen der folgenden Zeile zu Ihrer .bashrc
Datei (unter Linux) und Ausführen source ~/.bashrc
im Terminal:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Kredit / Quelle: saarrrr , eine weitere Frage zum Stapelaustausch
Es hört sich so an, als ob Sie die Konfigurationsdatei nicht speziell importieren möchten (was viele Nebenwirkungen und zusätzliche Komplikationen mit sich bringt), sondern sie nur ausführen und auf den resultierenden Namespace zugreifen möchten. Die Standardbibliothek bietet eine spezielle API in Form von runpy.run_path :
from runpy import run_path
settings = run_path("/path/to/file.py")
Diese Schnittstelle ist in Python 2.7 und Python 3.2+ verfügbar
result[name]
, result.get('name', default_value)
etc)
from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
Sie können auch so etwas tun und das Verzeichnis, in dem sich die Konfigurationsdatei befindet, zum Python-Ladepfad hinzufügen und dann einfach einen normalen Import durchführen, vorausgesetzt, Sie kennen den Namen der Datei im Voraus, in diesem Fall "config".
Chaotisch, aber es funktioniert.
configfile = '~/config.py'
import os
import sys
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
import config
def import_file(full_path_to_module):
try:
import os
module_dir, module_file = os.path.split(full_path_to_module)
module_name, module_ext = os.path.splitext(module_file)
save_cwd = os.getcwd()
os.chdir(module_dir)
module_obj = __import__(module_name)
module_obj.__file__ = full_path_to_module
globals()[module_name] = module_obj
os.chdir(save_cwd)
except:
raise ImportError
import_file('/home/somebody/somemodule.py')
except:
Sammelklausel ist selten eine gute Idee.
save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
this is already addressed by the standard library
Ja, aber Python hat die böse Angewohnheit, nicht abwärtskompatibel zu sein ... wie die überprüfte Antwort besagt, gibt es vor und nach 3.3 zwei verschiedene Möglichkeiten. In diesem Fall möchte ich lieber meine eigene universelle Funktion schreiben, als die Version im laufenden Betrieb zu überprüfen. Und ja, vielleicht ist dieser Code nicht allzu gut fehlergeschützt, aber er zeigt eine Idee (os.chdir (), über die ich noch nicht nachgedacht habe), auf deren Grundlage ich einen besseren Code schreiben kann. Daher +1.
Hier ist ein Code, der in allen Python-Versionen von 2.7-3.5 und wahrscheinlich sogar in anderen funktioniert.
config_file = "/tmp/config.py"
with open(config_file) as f:
code = compile(f.read(), config_file, 'exec')
exec(code, globals(), locals())
Ich habe es getestet. Es mag hässlich sein, aber bisher ist es das einzige, das in allen Versionen funktioniert.
load_source
nicht funktioniert, da sie das Skript importiert und dem Skript den Zugriff auf die Module und Globals zum Zeitpunkt des Imports ermöglicht.
Ich habe eine leicht modifizierte Version von @ SebastianRittaus wunderbarer Antwort (für Python> 3.4, glaube ich) entwickelt, mit der Sie eine Datei mit einer beliebigen Erweiterung als Modul laden können, spec_from_loader
anstatt spec_from_file_location
:
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)
Der Vorteil der expliziten Codierung des Pfads SourceFileLoader
besteht darin, dass die Maschine nicht versucht, den Dateityp aus der Erweiterung herauszufinden. Dies bedeutet, dass Sie .txt
mit dieser Methode so etwas wie eine Datei laden können , dies jedoch nicht spec_from_file_location
ohne Angabe des Loaders tun können, da dieser .txt
nicht vorhanden ist importlib.machinery.SOURCE_SUFFIXES
.
Meinst du laden oder importieren?
Sie können die sys.path
Liste bearbeiten, den Pfad zu Ihrem Modul angeben und dann Ihr Modul importieren. Beispiel: Ein Modul unter:
/foo/bar.py
Du könntest es tun:
import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
sys.path[0:0] = ['/foo']
Explicit is better than implicit.
Warum also nicht sys.path.insert(0, ...)
statt sys.path[0:0]
?
Ich glaube, Sie können das angegebene Modul verwenden imp.find_module()
und imp.load_module()
laden. Sie müssen den Modulnamen vom Pfad trennen, dh wenn Sie laden /home/mypath/mymodule.py
möchten, müssen Sie Folgendes tun:
imp.find_module('mymodule', '/home/mypath/')
... aber das sollte den Job erledigen.
Sie können das pkgutil
Modul (insbesondere die walk_packages
Methode) verwenden, um eine Liste der Pakete im aktuellen Verzeichnis abzurufen. Von dort aus ist es trivial, die importlib
gewünschten Module mithilfe der Maschinen zu importieren:
import pkgutil
import importlib
packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
mod = importlib.import_module(name)
# do whatever you want with module now, it's been imported!
Erstellen Sie das Python-Modul test.py
import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3
Erstellen Sie das Python-Modul test_check.py
from test import Client1
from test import Client2
from test import test3
Wir können das importierte Modul aus dem Modul importieren.
Dieser Bereich von Python 3.4 scheint äußerst schwierig zu verstehen zu sein! Mit ein bisschen Hacking mit dem Code von Chris Calloway als Anfang gelang es mir jedoch, etwas zum Laufen zu bringen. Hier ist die Grundfunktion.
def import_module_from_file(full_path_to_module):
"""
Import a module given the full path/filename of the .py file
Python 3.4
"""
module = None
try:
# Get module name and path from full path
module_dir, module_file = os.path.split(full_path_to_module)
module_name, module_ext = os.path.splitext(module_file)
# Get module "spec" from filename
spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)
module = spec.loader.load_module()
except Exception as ec:
# Simple error printing
# Insert "sophisticated" stuff here
print(ec)
finally:
return module
Dies scheint nicht veraltete Module aus Python 3.4 zu verwenden. Ich gebe nicht vor zu verstehen warum, aber es scheint innerhalb eines Programms zu funktionieren. Ich fand, dass Chris 'Lösung in der Kommandozeile funktionierte, aber nicht innerhalb eines Programms.
Ich sage nicht, dass es besser ist, aber der Vollständigkeit halber wollte ich die exec
Funktion vorschlagen , die sowohl in Python 2 als auch in Python 3 verfügbar
exec
ist. Sie können beliebigen Code entweder im globalen Bereich oder in einem internen Bereich ausführen. als Wörterbuch zur Verfügung gestellt.
Wenn Sie beispielsweise ein Modul in "/path/to/module
"mit der Funktion gespeichert haben foo()
, können Sie es folgendermaßen ausführen:
module = dict()
with open("/path/to/module") as f:
exec(f.read(), module)
module['foo']()
Dies macht es etwas expliziter, dass Sie Code dynamisch laden, und gewährt Ihnen zusätzliche Leistung, z. B. die Möglichkeit, benutzerdefinierte integrierte Funktionen bereitzustellen.
Wenn Ihnen der Zugriff über Attribute anstelle von Schlüsseln wichtig ist, können Sie eine benutzerdefinierte Diktatklasse für die Globals entwerfen, die einen solchen Zugriff bietet, z.
class MyModuleClass(dict):
def __getattr__(self, name):
return self.__getitem__(name)
Um ein Modul aus einem bestimmten Dateinamen zu importieren, können Sie den Pfad vorübergehend erweitern und den Systempfad in der Referenz für den endgültigen Block wiederherstellen :
filename = "directory/module.py"
directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]
path = list(sys.path)
sys.path.insert(0, directory)
try:
module = __import__(module_name)
finally:
sys.path[:] = path # restore
Das sollte funktionieren
path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
basename = os.path.basename(infile)
basename_without_extension = basename[:-3]
# http://docs.python.org/library/imp.html?highlight=imp#module-imp
imp.load_source(basename_without_extension, infile)
name, ext = os.path.splitext(os.path.basename(infile))
. Ihre Methode funktioniert aufgrund der vorherigen Einschränkung auf die Erweiterung .py. Außerdem sollten Sie das Modul wahrscheinlich in einen Variablen- / Wörterbucheintrag importieren.
Wenn wir Skripte im selben Projekt haben, aber in verschiedenen Verzeichnissen, können wir dieses Problem mit der folgenden Methode lösen.
In dieser Situation utils.py
ist insrc/main/util/
import sys
sys.path.append('./')
import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method
Ich habe ein Paket erstellt, das imp
für Sie verwendet wird. Ich nenne es import_file
und so wird es verwendet:
>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')
Sie können es bekommen bei:
http://pypi.python.org/pypi/import_file
oder bei
Paketmodule zur Laufzeit importieren (Python-Rezept)
http://code.activestate.com/recipes/223972/
###################
## #
## classloader.py #
## #
###################
import sys, types
def _get_mod(modulePath):
try:
aMod = sys.modules[modulePath]
if not isinstance(aMod, types.ModuleType):
raise KeyError
except KeyError:
# The last [''] is very important!
aMod = __import__(modulePath, globals(), locals(), [''])
sys.modules[modulePath] = aMod
return aMod
def _get_func(fullFuncName):
"""Retrieve a function object from a full dotted-package name."""
# Parse out the path, module, and function
lastDot = fullFuncName.rfind(u".")
funcName = fullFuncName[lastDot + 1:]
modPath = fullFuncName[:lastDot]
aMod = _get_mod(modPath)
aFunc = getattr(aMod, funcName)
# Assert that the function is a *callable* attribute.
assert callable(aFunc), u"%s is not callable." % fullFuncName
# Return a reference to the function itself,
# not the results of the function.
return aFunc
def _get_class(fullClassName, parentClass=None):
"""Load a module and retrieve a class (NOT an instance).
If the parentClass is supplied, className must be of parentClass
or a subclass of parentClass (or None is returned).
"""
aClass = _get_func(fullClassName)
# Assert that the class is a subclass of parentClass.
if parentClass is not None:
if not issubclass(aClass, parentClass):
raise TypeError(u"%s is not a subclass of %s" %
(fullClassName, parentClass))
# Return a reference to the class itself, not an instantiated object.
return aClass
######################
## Usage ##
######################
class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass
def storage_object(aFullClassName, allOptions={}):
aStoreClass = _get_class(aFullClassName, StorageManager)
return aStoreClass(allOptions)
Unter Linux funktioniert das Hinzufügen eines symbolischen Links in dem Verzeichnis, in dem sich Ihr Python-Skript befindet.
dh:
ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py
Python erstellt /absolute/path/to/script/module.pyc
und aktualisiert es, wenn Sie den Inhalt von ändern/absolute/path/to/module/module.py
Fügen Sie dann Folgendes in mypythonscript.py ein
from module import *
git
indem Sie Ihre verwenden und überprüfen, git status
um sicherzustellen, dass Ihre Änderungen am Skript tatsächlich zum Quelldokument zurückkehren und nicht im Äther verloren gehen.
Ich habe meine eigene globale und tragbare Importfunktion basierend auf dem importlib
Modul geschrieben für:
sys.path
oder von einem beliebigen Suchpfadspeicher abhängig zu sein .Die Beispiele Verzeichnisstruktur:
<root>
|
+- test.py
|
+- testlib.py
|
+- /std1
| |
| +- testlib.std1.py
|
+- /std2
| |
| +- testlib.std2.py
|
+- /std3
|
+- testlib.std3.py
Einschlussabhängigkeit und Reihenfolge:
test.py
-> testlib.py
-> testlib.std1.py
-> testlib.std2.py
-> testlib.std3.py
Implementierung:
Speicher für neueste Änderungen: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py
test.py :
import os, sys, inspect, copy
SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("test::SOURCE_FILE: ", SOURCE_FILE)
# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl
tkl.tkl_init(tkl)
# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()
tkl_import_module(SOURCE_DIR, 'testlib.py')
print(globals().keys())
testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test() # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test() # ... but reachable through the `globals` + `getattr`
tkl_import_module(SOURCE_DIR, 'testlib.py', '.')
print(globals().keys())
base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test() # does not reachable directly ...
globals()['testlib.std3'].std3_test() # ... but reachable through the `globals` + `getattr`
testlib.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')
# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')
print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)
def base_test():
print('base_test')
testlib.std1.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')
def std1_test():
print('std1_test')
testlib.std2.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)
def std2_test():
print('std2_test')
testlib.std3.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)
def std3_test():
print('std3_test')
Ausgabe ( 3.7.4
):
test::SOURCE_FILE: <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test
Getestet in Python 3.7.4
, 3.2.5
,2.7.16
Vorteile :
testlib.std.py
as testlib
, testlib.blabla.py
as testlib_blabla
usw.).sys.path
oder einem beliebigen Suchpfadspeicher ab.SOURCE_FILE
und SOURCE_DIR
zwischen Aufrufen von tkl_import_module
.3.4.x
und höher] Kann die Modul-Namespaces in verschachtelten tkl_import_module
Aufrufen mischen (z. B. named->local->named
oder local->named->local
so weiter).3.4.x
und höher] Kann globale Variablen / Funktionen / Klassen automatisch exportieren, von wo aus sie zu allen untergeordneten Modulen deklariert werden, die über tkl_import_module
(über die tkl_declare_global
Funktion) importiert wurden .Nachteile :
3.3.x
und niedriger] Erforderlich, tkl_import_module
in allen Modulen zu deklarieren, die aufrufen tkl_import_module
(Codeduplizierung)Update 1,2 (nur für 3.4.x
und höher):
In Python 3.4 und höher können Sie die Anforderung umgehen, tkl_import_module
in jedem Modul zu deklarieren, indem Sie tkl_import_module
in einem Modul der obersten Ebene deklarieren, und die Funktion würde sich in einem einzigen Aufruf auf alle untergeordneten Module auswirken (dies ist eine Art Selbstbereitstellungsimport).
Update 3 :
Funktion tkl_source_module
als analog zu Bash source
mit Support Execution Guard beim Import hinzugefügt (implementiert durch die Modulzusammenführung anstelle des Imports).
Update 4 :
Funktion tkl_declare_global
zum automatischen Exportieren einer globalen Modulvariablen in alle untergeordneten Module hinzugefügt, in denen eine globale Modulvariable nicht sichtbar ist, da sie nicht Teil eines untergeordneten Moduls ist.
Update 5 :
Alle Funktionen wurden in die Tacklelib-Bibliothek verschoben, siehe den obigen Link.
Es gibt ein spezielles Paket :
from thesmuggler import smuggle
# À la `import weapons`
weapons = smuggle('weapons.py')
# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')
# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')
Es wurde in allen Python-Versionen getestet (auch Jython und PyPy), kann jedoch je nach Größe Ihres Projekts zu viel des Guten sein.
Hinzufügen dieser zur Liste der Antworten, da ich nichts finden konnte, was funktionierte. Dies ermöglicht den Import kompilierter (pyd) Python-Module in 3.4:
import sys
import importlib.machinery
def load_module(name, filename):
# If the Loader finds the module name in this list it will use
# module_name.__file__ instead so we need to delete it here
if name in sys.modules:
del sys.modules[name]
loader = importlib.machinery.ExtensionFileLoader(name, filename)
module = loader.load_module()
locals()[name] = module
globals()[name] = module
load_module('something', r'C:\Path\To\something.pyd')
something.do_something()
Ganz einfache Möglichkeit: Angenommen, Sie möchten eine Datei mit dem relativen Pfad importieren. / .. / MyLibs / pyfunc.py
libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf
Aber wenn Sie es ohne Wache schaffen, können Sie endlich einen sehr langen Weg zurücklegen
Eine einfache Lösung importlib
anstelle des imp
Pakets (getestet für Python 2.7, obwohl es auch für Python 3 funktionieren sollte):
import importlib
dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")
Jetzt können Sie den Namespace des importierten Moduls direkt wie folgt verwenden:
a = module.myvar
b = module.myfunc(a)
Der Vorteil dieser Lösung ist, dass wir nicht einmal den tatsächlichen Namen des Moduls kennen müssen, das wir importieren möchten , um es in unserem Code zu verwenden. Dies ist nützlich, z. B. wenn der Pfad des Moduls ein konfigurierbares Argument ist.
sys.path
, was nicht für jeden Anwendungsfall geeignet ist.
sys.path.pop()
Diese Antwort ist eine Ergänzung zu Sebastian Rittaus Antwort auf den Kommentar: "Aber was ist, wenn Sie den Modulnamen nicht haben?" Dies ist eine schnelle und schmutzige Methode, um den wahrscheinlichen Namen des Python-Moduls mit einem Dateinamen zu versehen. Er geht nur den Baum hoch, bis ein Verzeichnis ohne __init__.py
Datei gefunden wird, und wandelt es dann wieder in einen Dateinamen um. Für Python 3.4+ (verwendet pathlib) ist dies sinnvoll, da Py2-Benutzer "imp" oder andere Methoden für relative Importe verwenden können:
import pathlib
def likely_python_module(filename):
'''
Given a filename or Path, return the "likely" python module name. That is, iterate
the parent directories until it doesn't contain an __init__.py file.
:rtype: str
'''
p = pathlib.Path(filename).resolve()
paths = []
if p.name != '__init__.py':
paths.append(p.stem)
while True:
p = p.parent
if not p:
break
if not p.is_dir():
break
inits = [f for f in p.iterdir() if f.name == '__init__.py']
if not inits:
break
paths.append(p.stem)
return '.'.join(reversed(paths))
Es gibt sicherlich Verbesserungsmöglichkeiten, und die optionalen __init__.py
Dateien erfordern möglicherweise andere Änderungen, aber wenn Sie __init__.py
im Allgemeinen haben, ist dies der Trick.
Ich denke, der beste Weg ist aus der offiziellen Dokumentation ( 29.1. Imp - Zugriff auf die Import-Interna ):
import imp
import sys
def __import__(name, globals=None, locals=None, fromlist=None):
# Fast path: see if the module has already been imported.
try:
return sys.modules[name]
except KeyError:
pass
# If any of the following calls raises an exception,
# there's a problem we can't handle -- let the caller handle it.
fp, pathname, description = imp.find_module(name)
try:
return imp.load_module(name, fp, pathname, description)
finally:
# Since we may exit via an exception, close fp explicitly.
if fp:
fp.close()