it-swarm-eu.dev

Wie importiere ich ein Modul unter Angabe des vollständigen Pfades?

Wie kann ich ein Python -Modul mit vollem Pfad laden? Beachten Sie, dass sich die Datei an einer beliebigen Stelle im Dateisystem befinden kann, da es sich um eine Konfigurationsoption handelt.

966
derfred

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()

Für Python 3.3 und 3.4 verwenden Sie:

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 entsprechende Komfortfunktionen für kompilierte Python -Dateien und DLLs.

Siehe auch http://bugs.python.org/issue21436 .

1116

Der Vorteil des Hinzufügens eines Pfades zu sys.path (anstelle von imp) besteht darin, dass der Import mehrerer Module aus einem einzelnen Paket 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
374
Daryl Spitzer

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 speziell dafür eine 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

20
ncoghlan

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 versucht exec_module beim Ausführen, 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 der Fehler "SystemError: Übergeordnetes Modul 'mymodule' nicht geladen, relativer Import nicht möglich" angezeigt wird. Sie müssen den Namen also binden, bevor Sie ihn laden. Der Grund dafür ist die fundamentale Invariante des relativen Importsystems: "Die Invariante besteht darin, dass Sie sys.modules ['spam'] und sys.modules ['spam.foo'] haben (wie Sie es nach dem obigen Import tun würden ), letzteres muss als foo-Attribut des ersteren erscheinen " wie hier besprochen .

20
Sam Grondahl

Um Ihr Modul zu importieren, müssen Sie sein Verzeichnis entweder vorübergehend oder dauerhaft zur Umgebungsvariablen hinzufügen.

Vorübergehend

import sys
sys.path.append("/path/to/my/modules/")
import my_module

Permanent

Hinzufügen der folgenden Zeile zu Ihrer .bashrc -Datei (unter Linux) und Ausführen von source ~/.bashrc im Terminal:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

Kredit/Quelle: saarrrr , eine andere Stapelwechselfrage

19
Miladiouss

Sie können auch so etwas tun und das Verzeichnis, in dem sich die Konfigurationsdatei befindet, in den Ladepfad Python einfügen und dann einfach einen normalen Import ausführen, vorausgesetzt, Sie kennen den Namen der Datei im Voraus in dieser 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
19
ctcherry

Du kannst den ... benutzen

load_source(module_name, path_to_file) 

methode von imp-Modul .

17
zuber

Ich habe eine leicht modifizierte Version von @ SebastianRittaus wunderbare Antwort (für Python> 3.4, denke ich) entwickelt, mit der Sie eine Datei mit einer beliebigen Erweiterung als Modul laden können mit spec_from_loader anstelle von 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 Codierung des Pfads in einem expliziten SourceFileLoader besteht darin, dass machinery nicht versucht, den Dateityp anhand der Erweiterung zu ermitteln. Dies bedeutet, dass Sie mit dieser Methode so etwas wie eine _.txt_-Datei laden können, dies jedoch nicht mit _spec_from_file_location_ ohne Angabe des Ladeprogramms, da _.txt_ nicht in importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Meinen Sie Laden oder Importieren?

Sie können die Liste sys.path bearbeiten, den Pfad zu Ihrem Modul angeben und dann Ihr Modul importieren. Zum Beispiel ein Modul gegeben an:

/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
12
Wheat

Hier ist ein Code, der in allen Python Versionen von 2.7-3.5 und wahrscheinlich auch in anderen Versionen 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, ist aber bisher das einzige, das in allen Versionen funktioniert.

12
sorin
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')
10
Chris Calloway

Ich glaube, Sie können imp.find_module() und imp.load_module() verwenden, um das angegebene Modul zu laden. Sie müssen den Modulnamen vom Pfad trennen, d. H., Wenn Sie /home/mypath/mymodule.py laden möchten, müssen Sie Folgendes tun:

imp.find_module('mymodule', '/home/mypath/')

... aber das sollte die Arbeit erledigen.

8
Matt

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.

4
abhimanyu

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 ganz einfach, die importlib -Maschinerie zu verwenden, um die gewünschten Module 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!
_
3
bob_twinkles

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)
3
Hengjie

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 3. exec verfügbar ist Führen Sie beliebigen Code entweder im globalen Bereich oder in einem internen Bereich aus, der als Wörterbuch bereitgestellt wird.

Wenn Sie beispielsweise ein Modul in "/path/to/module "mit der Funktion foo() gespeichert haben, können Sie es folgendermaßen ausführen:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

Das macht es etwas expliziter, dass Sie Code dynamisch laden, und verleiht Ihnen zusätzliche Leistung, z. B. die Möglichkeit, benutzerdefinierte Buildins bereitzustellen.

Und wenn Ihnen der Zugriff über Attribute anstelle von Schlüsseln wichtig ist, können Sie eine benutzerdefinierte Diktatklasse für die Globalen entwerfen, die einen solchen Zugriff ermöglicht, z.

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)
3
yoniLavi

Dieser Bereich von Python 3.4 scheint extrem umständlich zu sein! Mit ein bisschen Hacking und dem Code von Chris Calloway als Start 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 auf der Kommandozeile funktionierte, aber nicht in einem Programm.

3
Redlegjed

Um ein Modul aus einem bestimmten Dateinamen zu importieren, können Sie den Pfad vorübergehend erweitern und den Systempfad im finally-Block reference: 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
3
Peter Zhu

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)
2
user10370

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 /absolute/path/to/module/module.py ändern.

fügen Sie dann Folgendes in mypythonscript.py ein

from module import *
2
user2760152

Ich habe ein Paket erstellt, das imp für Sie verwendet. 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

http://code.google.com/p/import-file/

2
ubershmekel

ganz einfach: Angenommen, Sie möchten eine Importdatei mit einem relativen Pfad ../../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

1
Andrei Keino

Eine einfache Lösung mit 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 müssen nicht einmal den tatsächlichen Namen des Moduls kennen, das wir importieren möchten, um es in unserem Code zu verwenden. Dies ist nützlich, z.B. falls der Pfad des Moduls ein konfigurierbares Argument ist.

1
Ataxias

Dies zur Liste der Antworten hinzufügen, da ich nichts gefunden habe, was funktioniert hat. Dies ermöglicht den Import von kompilierten (pyd) python Modulen 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()
0
David

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 unsaubere Methode, um den wahrscheinlichen python - Modulnamen mit einem Dateinamen zu ermitteln. Sie durchsucht den Baum nur, bis ein Verzeichnis ohne __init__.py -Datei gefunden wird, und wandelt es dann wieder in ein Dateiname. Für Python 3.4+ (verwendet pathlib) ist dies sinnvoll, da Py2-Benutzer "imp" oder andere Methoden zum Ausführen relativer 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.