it-swarm-eu.dev

Jak importovat modul s plnou cestou?

Jak mohu načíst modul Python s jeho plnou cestou? Všimněte si, že soubor může být kdekoli v souborovém systému, protože se jedná o možnost konfigurace.

922
derfred

Pro použití v jazyce Python 3.5+:

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

Pro Python 3.3 a 3.4 použijte:

from importlib.machinery import SourceFileLoader

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

(Ačkoli toto bylo v Pythonu 3.4 odmítnuto.)

Pro Python 2 použijte:

import imp

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

Pro kompilované soubory Pythonu a DLL existují ekvivalentní funkce.

Viz také http://bugs.python.org/issue21436 .

1055
Sebastian Rittau

Výhodou přidání cesty k sys.path (přes použití imp) je to, že zjednodušuje věci při importu více než jednoho modulu z jednoho balíčku. Například:

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
358
Daryl Spitzer

Můžete také udělat něco takového a přidat adresář, do kterého konfigurační soubor sedí na cestě k Pythonu, a pak stačí udělat normální import, za předpokladu, že znáte název souboru předem, v tomto případě "config".

Messy, ale funguje to.

configfile = '~/config.py'

import os
import sys

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

import config
19
ctcherry

Zní to, jako byste nechtěli specificky importovat konfigurační soubor (který má spoustu vedlejších účinků a dalších komplikací), stačí jej spustit a mít přístup k výslednému jmennému prostoru. Standardní knihovna poskytuje API speciálně pro toto ve formě runpy.run_path :

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

Toto rozhraní je dostupné v Pythonu 2.7 a Pythonu 3.2+

19
ncoghlan

Můžete použít

load_source(module_name, path_to_file) 

metoda z imp modul .

16
zuber

Přišel jsem s mírně upravenou verzí nádherné odpovědi @ SebastianRittau (pro Python> 3.4 myslím), která vám umožní nahrát soubor s libovolnou příponou jako modul pomocí spec_from_loader namísto 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)

Výhodou kódování cesty v explicitní SourceFileLoader je, že strojní zařízení se nepokusí zjistit typ souboru z rozšíření. To znamená, že pomocí této metody můžete načíst něco jako soubor .txt, ale nebylo by to možné s spec_from_file_location bez určení zavaděče, protože .txt není v importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Myslíte zatížení nebo import?

Můžete manipulovat se seznamem sys.path určit cestu k modulu a poté importovat modul. Například daný modul na adrese:

/foo/bar.py

Můžete to udělat:

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

Pokud váš modul nejvyšší úrovně není soubor, ale je zabalen jako adresář s __init__.py, pak přijaté řešení funguje téměř, ale ne zcela. V Pythonu 3.5+ je nutný následující kód (všimněte si přidaného řádku, který začíná '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)

Bez tohoto řádku, když je vykonán exec_module, pokusí se navázat relativní importy v nejvyšší úrovni __init__.py na název modulu nejvyšší úrovně - v tomto případě "mymodule". "Mymodule" ještě není načten, takže dostanete chybu "SystemError: mymodule rodičovského modulu" není načten, nelze provádět relativní import ". Před načtením je tedy nutné tento název svázat. Důvodem je základní invariant relativního systému importu: "Neměnné držení je, že pokud máte sys.modules ['spam'] a sys.modules ['spam.foo'] (stejně jako po výše uvedeném importu) ), musí se objevit jako atribut foo bývalého " jak je zde popsáno .

12
Sam Grondahl

Chcete-li modul importovat, musíte jej dočasně nebo trvale přidat do proměnné prostředí.

Dočasně

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

Trvale

Přidání následujícího řádku do souboru .bashrc (v linuxu) a excecute source ~/.bashrc v terminálu:

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

Credit/Source: saarrrr , další otázka stohování

11
Miladiouss

Zde je nějaký kód, který funguje ve všech verzích Pythonu, od 2.7-3.5 a pravděpodobně i další.

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

Testoval jsem to. To může být ošklivé, ale zatím je to jediné, které funguje ve všech verzích.

11
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

Věřím, že můžete použít imp.find_module() a imp.load_module() pro načtení zadaného modulu. Budete muset rozdělit název modulu mimo cestu, tj. Pokud byste chtěli načíst soubor /home/mypath/mymodule.py, který musíte provést:

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

... ale to by mělo dostat práci.

8
Matt

Vytvořte python modul test.py

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

Vytvořte python modul test_check.py

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

Importovaný modul můžeme importovat z modulu.

3
abhimanyu

Modul pkgutil (konkrétně metoda walk_packages method) můžete použít k získání seznamu balíků v aktuálním adresáři. Odtamtud je triviální použít stroj importlib k importu požadovaných modulů:

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

To by mělo fungovat

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

Neříkám, že je to lepší, ale pro úplnost jsem chtěl navrhnout exec function, který je k dispozici v obou python 2 a 3. exec umožňuje provádět libovolný kód v globálním rozsahu, nebo ve vnitřním rozsahu, poskytovaném jako slovník.

Pokud máte například v souboru "/path/to/module uložen modul s funkcí foo(), můžete jej spustit následujícím způsobem:

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

To je o něco více explicitní, že načítáte kód dynamicky, a uděluje vám dodatečnou energii, například schopnost poskytovat vlastní vestavěné moduly.

A pokud je pro vás důležitý přístup prostřednictvím atributů, místo klíčů, můžete navrhnout vlastní třídu dict pro globály, která takový přístup poskytuje, např .:

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

Tato oblast Pythonu 3.4 se zdá být nesmírně mučivá! Nicméně s trochou hackování používajícího kód od Chrisa Callowaye se mi podařilo dostat něco do práce. Zde je základní funkce.

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

Zdá se, že se jedná o nepoužívané moduly z Pythonu 3.4. Nepředstírám, že chápu proč, ale zdá se, že to funguje v rámci programu. Našel jsem Chrisovo řešení na příkazovém řádku, ale ne zevnitř programu.

3
Redlegjed

Chcete-li importovat modul z daného názvu souboru, můžete dočasně rozšířit cestu a obnovit systémovou cestu v posledním bloku reference:

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

Importovat moduly balíku za běhu (Recept Pythonu)

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

V Linuxu se přidává symbolický odkaz do adresáře, ve kterém se nachází váš skript python.

tj:

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

python vytvoří /absolute/path/to/script/module.pyc a bude jej aktualizovat, pokud změníte obsah /absolute/path/to/module/module.py

pak v mypythonscript.py

from module import *
2
user2760152

Udělal jsem balíček, který pro vás používá imp. Říkám tomu import_file a je to, jak se používá:

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

Můžete ji získat na adrese:

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

nebo na

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

2
ubershmekel

docela jednoduchý způsob: předpokládejme, že chcete importovat soubor s relativní cestou ../../MyLibs/pyfunc.py


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

Ale pokud to uděláte bez stráže, můžete konečně dostat velmi dlouhou cestu

1
Andrei Keino

Jednoduché řešení pomocí importlib namísto balíčku imp (testováno pro Python 2.7, i když by mělo fungovat i pro Python 3):

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

Nyní můžete přímo použít jmenný prostor importovaného modulu, jako je tento:

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

Výhodou tohoto řešení je, že ani nemusíme znát skutečný název modulu, který bychom chtěli importovat , abychom jej mohli použít v našem kódu. To je užitečné, např. v případě, že cesta modulu je konfigurovatelný argument.

1
Ataxias

Přidání tohoto do seznamu odpovědí, protože jsem nemohl najít nic, co by fungovalo. To umožní import kompilovaných (pyd) python modulů v 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

Tato odpověď je doplňkem odpovědi Sebastiana Rittaua, který odpověděl na komentář: "Ale co když nemáte název modulu?" Jedná se o rychlý a špinavý způsob získání pravděpodobného názvu pythonového modulu, který je pojmenován názvem souboru - jde pouze nahoru, dokud nenajde adresář bez souboru __init__.py a pak ho vrátí zpět do názvu souboru. Pro Python 3.4+ (používá pathlib), který dává smysl, protože Py2 lidé mohou používat "imp" nebo jiné způsoby provádění relativních importů:

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

Existují jistě možnosti zlepšení a volitelné soubory __init__.py mohou vyžadovat další změny, ale pokud máte __init__.py obecně, je to trik.