Frage

Wie kann ich ein Python-Modul aufgrund seiner vollständigen Pfad laden? Beachten Sie, dass die Datei kann überall im Dateisystem sein, da es eine Konfigurationsoption ist.

War es hilfreich?

Lösung

Für Python 3.5+ Verwendung:

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 Verwendung:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(Obwohl dies in Python 3.4 ist veraltet.)

Für Python 2 Verwendung:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Es gibt gleichwertige Komfortfunktionen für kompilierte Python-Dateien und DLLs.

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

Andere Tipps

Der Vorteil, einen Weg zu sys.path der Zugabe (über mit imp) ist, dass es Dinge vereinfacht, wenn mehr als ein Modul aus einem einzigen Paket zu importieren. 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

Sie können auch etwas tun und das Verzeichnis hinzufügen, die die Konfigurationsdatei in der Python Lastweg sitzt, und dann tun, nur einen normalen Import, vorausgesetzt, Sie den Namen der Datei im Voraus wissen, in diesem Fall " config“.

Unordentlich, aber es funktioniert.

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

Es klingt wie Sie wollen nicht speziell auf die Konfigurationsdatei importieren (die eine ganze Reihe von Nebenwirkungen und zusätzliche Komplikationen beteiligt hat), wollen Sie gerade, um sie auszuführen, und in der Lage, die resultierende Namespace zuzugreifen. Die Standardbibliothek stellt eine API speziell für das in Form von runpy.run_path

from runpy import run_path
settings = run_path("/path/to/file.py")

Diese Schnittstelle in Python verfügbar ist 2.7 und Python 3.2 +

Sie können mit der

load_source(module_name, path_to_file) 

Methode von imp Modul .

Wenn Ihr Top-Level-Modul nicht eine Datei ist, sondern als ein Verzeichnis mit __init__.py verpackt, dann fast der akzeptierten Lösung funktioniert, aber nicht ganz. In Python 3.5+ der folgende Code benötigt (beachten Sie die zusätzliche 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, wenn exec_module ausgeführt wird, versucht es relativ Importe in Ihrem Top-Level-__init__.py auf die obersten Ebene Modulnamen zu binden - in diesem Fall „mymodule“. Aber „mymodule“ ist noch nicht geladen, so dass Sie die Fehlermeldung „Systemerror: Parent-Modul‚mymodule‘nicht geladen wird, nicht relativ Import durchführen“ bekommen. So müssen Sie den Namen binden, bevor Sie es laden. Der Grund hierfür ist die fundamentale Invariante des relativen Importsystem: „Die Invariante Halte ist, dass, wenn Sie sys.modules [‚Spam‘] und sys.modules [‚spam.foo‘] (wie man es nach dem oben genannten Import haben ), wobei die letztere der ersteren erscheinen als foo Attribut muss“ wie hier diskutiert .

Ich habe mit einer leicht modifizierten Version von @ SebastianRittau wunderbaren Antwort kommen (für Python> 3.4 glaube ich), die Ihnen erlauben, eine Datei mit einer beliebigen Erweiterung als Modul zu laden mit spec_from_loader statt 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 Pfades in einem expliziten SourceFileLoader ist, dass die Maschinen nicht zu Figur versuchen aus der Art der Datei, aus der Erweiterung. Das bedeutet, dass Sie so etwas wie eine .txt Datei mit dieser Methode laden können, aber man konnte es nicht mit spec_from_file_location tun, ohne die Lader Angabe weil .txt ist nicht in importlib.machinery.SOURCE_SUFFIXES .

Hier ist ein Code, der in allen Python-Versionen funktioniert, 2,7-3,5 und wahrscheinlich auch andere.

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 kann hässlich sein, aber bisher ist die einzige, die in allen Versionen funktioniert.

Ihr Modul importieren, müssen Sie dessen Verzeichnis der Umgebungsvariablen hinzuzufügen, entweder vorübergehend oder endgültig einzustellen.

Vorübergehend

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

Dauerhaft

Wenn Sie folgende Zeile in der .bashrc-Datei (unter Linux) und excecute source ~/.bashrc im Terminal:

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

Kredit / Quelle: saarrrr , eine andere Stack Frage

Wollen Sie laden oder importieren?

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

/foo/bar.py

Sie können tun:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
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')

Ich glaube, Sie können imp.find_module() und imp.load_module() die angegebene Modul zu laden. Sie werden den Modulnamen aufgeteilt müssen der Pfad ab, das heißt, wenn Sie laden wollte /home/mypath/mymodule.py Sie tun müssen, würde:

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

... aber das sollte den Job erledigen.

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)

Sie können die pkgutil Modul verwenden (speziell die walk_packages Verfahren), um eine Liste der Pakete im aktuellen Verzeichnis zu erhalten. Von dort ist es trivial, die importlib Maschinen zu verwenden, um die Module zu importieren Sie wollen:

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!

Dieser Bereich von Python 3.4 scheint extrem gewunden zu sein, zu verstehen! Doch mit ein wenig Hacking den Code von Chris Calloway als Start mit schaffte ich 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 von Python 3.4 zu verwenden. Ich behaupte nicht, zu verstehen, warum, aber es scheint, aus einem Programm zu arbeiten. Ich fand Chris' Lösung auf der Kommandozeile gearbeitet, aber nicht aus dem Inneren eines Programms.

Ich sage nicht, dass es besser ist, aber aus Gründen der Vollständigkeit, wollte ich die exec Funktion, in beiden Pythons 2 und 3. exec können Sie entweder im globalen Bereich, beliebigen Code auszuführen, oder in einem internen Umfang, als Wörterbuch zur Verfügung gestellt.

Zum Beispiel, wenn Sie ein Modul in "/path/to/module gespeichert haben“mit der Funktion foo(), man könnte es laufen durch den folgenden Aktionen ausführen:

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

Das macht es etwas deutlicher, dass Sie Code dynamisch einlegen, und gewährt Ihnen eine zusätzliche Leistung, wie die Fähigkeit, benutzerdefinierte builtins bereitzustellen.

Und wenn durch Attribute Zugriff hat, statt Schlüssel für Sie wichtig ist, können Sie eine benutzerdefinierte Klasse dict Design für die Globals, die diesen Zugang bereitstellt, z.

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

Um ein Modul aus einem bestimmten Dateinamen zu importieren, können Sie vorübergehend den Weg verlängern, und Wiederherstellen der Systempfad in dem schließlich ein href Block <= „http://effbot.org/zone/import-string.htm“ rel = "nofollow"> Referenz:

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

Erstellen Python-Modul test.py

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

Erstellen Python-Modul test_check.py

from test import Client1
from test import Client2
from test import test3

Wir können das importierte Modul aus Modul importiert werden.

Ich habe ein Paket, das imp für Sie verwendet. Ich nenne es import_file und das ist, wie es verwendet wird:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

Sie können es abrufen:

http://pypi.python.org/pypi/import_file

oder

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

Import Paket Module zur Laufzeit (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)

In Linux, einen symbolischen Link im Verzeichnis Hinzufügen Ihres Python-Skript Werke befindet.

ie:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

Python wird /absolute/path/to/script/module.pyc erstellen und es wird aktualisiert, wenn Sie den Inhalt /absolute/path/to/module/module.py ändern

dann sind die folgenden in mypythonscript.py

from module import *

ganz einfache Art und Weise: Angenommen, Sie Importdatei mit relativen Pfaden wollen ../../ MyLibs / pyfunc.py


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

Aber wenn man es ohne Schutz machen kann man schließlich einen sehr langen Weg bekommen

Eine einfache Lösung mit importlib anstelle des imp Pakets (getestet für Python 2.7, obwohl es für Python 3 funktionieren soll):

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 direkt den Namensraum des importierten Modul verwenden, wie folgt aus:

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 wir importieren möchten, um es in unserem Code zu verwenden. Dies ist nützlich, z.B. für den Fall, ist der Pfad des Moduls ein konfigurierbarer Argument.

Das Hinzufügen dieser in die Liste der Antworten, wie ich konnte nichts finden, die funktioniert. Dies wird in 3.4 Einfuhr von kompilierten (PYD) Python-Module ermöglichen:

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

Diese Antwort ist eine Ergänzung zu Sebastian Rittau Antwort auf den Kommentar antwortet: „Was aber, wenn Sie den Namen des Moduls nicht haben“ Dies ist eine schnelle und schmutzige Art und Weise, die wahrscheinlich Python-Modul Namen einen Dateinamen gegeben bekommen - es geht nur auf den Baum, bis er ein Verzeichnis ohne __init__.py Datei findet, und dann wird es wieder in einen Dateinamen an. Für Python 3.4+ (verwendet pathlib), was Sinn macht, da Py2 Menschen „imp“ oder andere Art und Weise zu tun, relativ 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 Möglichkeiten für Verbesserungen, und die optionalen __init__.py Dateien könnten weitere Änderungen erforderlich machen, aber wenn man im Allgemeinen __init__.py haben, dies funktioniert der Trick.

Der beste Weg, denke ich, ist von der offiziellen Dokumentation ( 29.1. Imp - Zugang der 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()
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top