Hoe importeer ik een module met het volledige pad?

Hoe kan ik een Python-module laden gezien het volledige pad? Merk op dat het bestand overal in het bestandssysteem kan zijn, aangezien het een configuratieoptie is.


Antwoord 1, autoriteit 100%

Voor Python 3.5+ gebruik:

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

Gebruik voor Python 3.3 en 3.4:

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

(Hoewel dit is verouderd in Python 3.4.)

Gebruik voor Python 2:

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

Er zijn gelijkwaardige gemaksfuncties voor gecompileerde Python-bestanden en DLL’s.

Zie ook http://bugs.python.org/issue21436.


Antwoord 2, autoriteit 33%

Het voordeel van het toevoegen van een pad aan sys.path (boven het gebruik van imp) is dat het dingen vereenvoudigt bij het importeren van meer dan één module uit een enkel pakket. Bijvoorbeeld:

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

Antwoord 3, autoriteit 5%

Als je module op het hoogste niveau geen bestand is maar is verpakt als een map met __init__.py, dan werkt de geaccepteerde oplossing bijna, maar niet helemaal. In Python 3.5+ is de volgende code nodig (let op de toegevoegde regel die begint met ‘sys.modules’):

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)

Zonder deze regel, wanneer exec_module wordt uitgevoerd, probeert het relatieve imports in uw topniveau __init__.py te binden aan de modulenaam op het hoogste niveau — in dit geval “mymodule”. Maar “mijnmodule” is nog niet geladen, dus je krijgt de foutmelding “SystemError: Parent module ‘mymodule’ not loaded, cannot perform relatieve import”. U moet de naam dus binden voordat u deze laadt. De reden hiervoor is de fundamentele invariant van het relatieve importsysteem: “De invariante holding is dat als je sys.modules[‘spam’] en sys.modules[‘spam.foo’] hebt (zoals je zou doen na de bovenstaande import ), moet de laatste verschijnen als het foo-attribuut van de eerste” zoals hier besproken.


Antwoord 4, autoriteit 5%

Om je module te importeren, moet je zijn directory toevoegen aan de omgevingsvariabele, tijdelijk of permanent.

Tijdelijk

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

Permanent

De volgende regel toevoegen aan uw .bashrc(of alternatief) bestand in Linux
en voer source ~/.bashrc(of alternatief) uit in de terminal:

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

Credit / Source: Saarrrr , Nog een stackexchange-vraag


5, Autoriteit 2%

Het klinkt alsof je het configuratiebestand (dat veel bijwerkingen en aanvullende complicaties heeft, niet specifiek wilt importeren), wil je het gewoon rennen en hebben toegang tot de resulterende naamruimte. De standaardbibliotheek biedt een API specifiek voor dat in de vorm van runpy.run_path :

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

Die interface is beschikbaar in Python 2.7 en Python 3.2 +


6

U kunt ook zoiets doen en de map toevoegen die het configuratiebestand zit in het Python-laadpad en vervolgens een normale importeren, ervan uitgaande dat u de naam van het bestand vooraf bent, in dit geval ” config “.

rommelig, maar het werkt.

configfile = '~/config.py'
import os
import sys
sys.path.append(os.path.dirname(os.path.expanduser(configfile)))
import config

7

U kunt de

gebruiken

load_source(module_name, path_to_file) 

Methode van creat module .


8

bedoelt u lading of import?

U kunt de lijst sys.pathmanipuleren Geef het pad op uw module op en importeer vervolgens uw module. Bijvoorbeeld, gezien een module op:

/foo/bar.py

u zou kunnen doen:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar

9

Ik heb een enigszins gewijzigde versie van @ Sebastianrittau’s prachtige antwoord (voor Python & GT; 3.4 denk ik denk) , waarmee u een bestand kunt laden met een extensie als een module met spec_from_loaderin plaats van 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)

Het voordeel van het coderen van het pad in een expliciete SourceFileLoaderis dat de machineszal niet proberen het type bestand van de extensie te achterhalen. Dit betekent dat je met deze methode zoiets als een .txt-bestand kunt laden, maar dat je dit niet kunt doen met spec_from_file_locationzonder de lader te specificeren omdat .txtstaat niet in importlib.machinery.SOURCE_SUFFIXES.


Antwoord 10

Hier is wat code die werkt in alle Python-versies, van 2.7-3.5 en waarschijnlijk zelfs andere.

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

Ik heb het getest. Het is misschien lelijk, maar tot nu toe is het de enige die in alle versies werkt.


Antwoord 11

u kunt dit doen met __ import __ en chdir

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 Exception as e:
        raise ImportError(e)
    return module_obj
import_file('/home/somebody/somemodule.py')

Antwoord 12

Als we scripts in hetzelfde project maar in verschillende directory’s hebben, kunnen we dit probleem op de volgende manier oplossen.

In deze situatie bevindt utils.pyzich in src/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

Antwoord 13

Ik geloof dat je imp.find_module()en imp.load_module()om de opgegeven module te laden. Je moet de modulenaam van het pad afsplitsen, d.w.z. als je /home/mypath/mymodule.pywilt laden, moet je het volgende doen:

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

…maar dat zou de klus moeten klaren.


Antwoord 14

U kunt de module pkgutilgebruiken (met name de walk_packagesmethode) om een lijst te krijgen van de pakketten in de huidige directory. Van daaruit is het triviaal om de importlib-machinerie te gebruiken om de gewenste modules te importeren:

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!

Antwoord 15

Maak python-module test.py

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

Maak python-module test_check.py

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

We kunnen de geïmporteerde module uit de module importeren.


Antwoord 16

Dit gedeelte van Python 3.4 lijkt buitengewoon lastig te begrijpen! Maar met een beetje hacken met de code van Chris Calloway als begin, lukte het me om iets werkend te krijgen. Dit is de basisfunctie.

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

Dit lijkt niet-verouderde modules van Python 3.4 te gebruiken. Ik pretendeer niet te begrijpen waarom, maar het lijkt te werken vanuit een programma. Ik ontdekte dat de oplossing van Chris werkte op de opdrachtregel, maar niet vanuit een programma.


Antwoord 17

Er is een pakketdat hier specifiek aan is gewijd:

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

Het is getest in alle Python-versies (ook Jython en PyPy), maar het kan overdreven zijn, afhankelijk van de grootte van je project.


Antwoord 18

Ik heb een pakket voor je gemaakt dat impgebruikt. Ik noem het import_fileen zo wordt het gebruikt:

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

Je kunt het krijgen op:

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

of bij

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


Antwoord 19

Ik zeg niet dat het beter is, maar voor de volledigheid wilde ik de exec-functie, beschikbaar in zowel python 2 als 3.
Met execkunt u willekeurige code uitvoeren in de globale scope of in een interne scope, geleverd als een woordenboek.

Als u bijvoorbeeld een module hebt opgeslagen in "/path/to/module” met de functie foo(), kunt u deze als volgt uitvoeren :

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

Dit maakt het wat explicieter dat je code dynamisch laadt, en geeft je wat extra kracht, zoals de mogelijkheid om aangepaste ingebouwde functies te bieden.

En als toegang via attributen in plaats van sleutels belangrijk voor je is, kun je een aangepaste dict-klasse ontwerpen voor de globals, die dergelijke toegang biedt, bijvoorbeeld:

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

Antwoord 20

Als u een module van een bepaalde bestandsnaam wilt importeren, kunt u het pad tijdelijk uitbreiden en het systeempad herstellen in het slotblok referentie:

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

Antwoord 21

Dit zou moeten werken

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)

Antwoord 22

Pakketmodules importeren tijdens runtime (Python-recept)

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)

23

In Linux, een symbolische koppeling toevoegen in de map is uw Python-script aan het werk.

IE:

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

Python maakt /absolute/path/to/script/module.pycen zal het updaten als u de inhoud van /absolute/path/to/module/module.py

Neem vervolgens het volgende in Mypythonscript.py

from module import *

24

Een eenvoudige oplossing met importlibin plaats van de imppakket (getest voor python 2.7, hoewel het ook voor Python 3 moet werken):

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

Nu kunt u direct de naamruimte van de geïmporteerde module gebruiken, zoals deze:

a = module.myvar
b = module.myfunc(a)

Het voordeel van deze oplossing is dat we niet eens de werkelijke naam van de module die we willen importeren, hoeven te wetenom deze in onze code te gebruiken. Dit is handig, b.v. in het geval dat het pad van de module een configureerbaar argument is.


Antwoord 25

Dit toevoegen aan de lijst met antwoorden omdat ik niets kon vinden dat werkte. Hierdoor kunnen gecompileerde (pyd) python-modules in 3.4 worden geïmporteerd:

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

Antwoord 26

vrij eenvoudige manier: stel dat je een bestand wilt importeren met relatief pad ../../MyLibs/pyfunc.py


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

Maar als je het zonder bewaker haalt, kun je eindelijk een heel lang pad krijgen


Antwoord 27

Dit zijn mijn 2 hulpprogramma-functies die alleen pathlib gebruiken. Het leidt de modulenaam af van het pad
Standaard laadt het recursief alle python-bestanden uit mappen en vervangt init.py door de naam van de bovenliggende map. Maar je kunt ook een Pad en/of een glob opgeven om bepaalde bestanden te selecteren.

from pathlib import Path
from importlib.util import spec_from_file_location, module_from_spec
from typing import Optional
def get_module_from_path(path: Path, relative_to: Optional[Path] = None):
    if not relative_to:
        relative_to = Path.cwd()
    abs_path = path.absolute()
    relative_path = abs_path.relative_to(relative_to.absolute())
    if relative_path.name == "__init__.py":
        relative_path = relative_path.parent
    module_name = ".".join(relative_path.with_suffix("").parts)
    mod = module_from_spec(spec_from_file_location(module_name, path))
    return mod
def get_modules_from_folder(folder: Optional[Path] = None, glob_str: str = "*/**/*.py"):
    if not folder:
        folder = Path(".")
    mod_list = []
    for file_path in sorted(folder.glob(glob_str)):
        mod_list.append(get_module_from_path(file_path))
    return mod_list

Antwoord 28

Toevoegen aan Sebastian Rittau:
In ieder geval voor CPython is er pydoc, en hoewel niet officieel aangegeven, importeren bestanden is wat doet:

from pydoc import importfile
module = importfile('/path/to/module.py')

PS.Voor de volledigheid is er op het moment van schrijven een verwijzing naar de huidige implementatie: pydoc.py, en ik ben blij te kunnen zeggen dat in de geest van xkcd 1987het gebruikt geen van de in uitgave 21436 genoemde implementaties — tenminste, niet letterlijk.


Antwoord 29

Dit antwoord is een aanvulling op het antwoord van Sebastian Rittau op de opmerking: “maar wat als je de modulenaam niet hebt?” Dit is een snelle en vuile manier om de waarschijnlijke naam van de python-module een bestandsnaam te geven — het gaat gewoon omhoog in de boom totdat het een map vindt zonder een __init__.py-bestand en verandert het dan weer in een bestandsnaam. Voor Python 3.4+ (gebruikt pathlib), wat logisch is omdat Py2-mensen “imp” of andere manieren kunnen gebruiken om relatieve importen uit te voeren:

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

Er zijn zeker mogelijkheden voor verbetering, en de optionele __init__.py-bestanden kunnen andere wijzigingen vereisen, maar als u __init__.pyIn het algemeen, dit doet de truc .

Other episodes