it-swarm-id.com

Bagaimana cara mengatur modul dengan path lengkap?

Bagaimana saya bisa memuat modul Python diberikan path lengkapnya? Perhatikan bahwa file tersebut dapat berada di mana saja di sistem file, karena ini merupakan opsi konfigurasi.

922
derfred

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

Untuk Python 3.3 dan 3.4 gunakan:

from importlib.machinery import SourceFileLoader

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

(Meskipun ini sudah usang dalam Python 3.4.)

Untuk penggunaan Python 2:

import imp

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

Ada fungsi kenyamanan yang setara untuk file Python dan DLL yang dikompilasi.

Lihat juga http://bugs.python.org/issue21436 .

1055
Sebastian Rittau

Keuntungan menambahkan path ke sys.path (lebih dari menggunakan imp) adalah bahwa hal itu menyederhanakan hal-hal ketika mengimpor lebih dari satu modul dari satu paket. Sebagai contoh:

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

Anda juga dapat melakukan sesuatu seperti ini dan menambahkan direktori tempat file konfigurasi berada di jalur pemuatan Python, dan kemudian hanya melakukan impor normal, dengan asumsi Anda tahu nama file di muka, dalam hal ini "config".

Berantakan, tapi berhasil.

configfile = '~/config.py'

import os
import sys

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

import config
19
ctcherry

Sepertinya Anda tidak ingin mengimpor file konfigurasi secara khusus (yang memiliki banyak efek samping dan komplikasi tambahan), Anda hanya ingin menjalankannya, dan dapat mengakses namespace yang dihasilkan. Pustaka standar menyediakan API khusus untuk itu dalam bentuk runpy.run_path :

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

Antarmuka itu tersedia dalam Python 2.7 dan Python 3.2+

19
ncoghlan

Anda dapat menggunakan

load_source(module_name, path_to_file) 

metode dari modul imp .

16
zuber

Saya telah datang dengan versi yang sedikit dimodifikasi dari @ Jawaban indah SebastianRittau (untuk Python> 3,4 saya pikir), yang akan memungkinkan Anda untuk memuat file dengan ekstensi apa pun sebagai modul menggunakan spec_from_loader bukannya 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)

Keuntungan dari pengodean path secara eksplisit SourceFileLoader adalah bahwa machinery tidak akan mencoba mencari tahu tipe file dari ekstensi. Ini berarti bahwa Anda dapat memuat sesuatu seperti file .txt menggunakan metode ini, tetapi Anda tidak dapat melakukannya dengan spec_from_file_location tanpa menentukan loader karena .txt tidak ada di importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Apakah maksud Anda memuat atau mengimpor?

Anda dapat memanipulasi daftar sys.path menentukan jalur ke modul Anda, lalu mengimpor modul Anda. Misalnya, diberikan modul di:

/foo/bar.py

Anda bisa melakukannya:

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

Jika modul tingkat atas Anda bukan file tetapi dikemas sebagai direktori dengan __init__.py, maka solusi yang diterima hampir berfungsi, tetapi tidak cukup. Dalam Python 3.5+ kode berikut diperlukan (perhatikan baris yang ditambahkan yang dimulai dengan '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)

Tanpa baris ini, ketika exec_module dijalankan, ia mencoba untuk mengikat impor relatif di __init__.py tingkat atas ke nama modul tingkat atas - dalam hal ini "mymodule". Tetapi "mymodule" belum dimuat sehingga Anda akan mendapatkan kesalahan "SystemError: Parent module 'mymodule' tidak dimuat, tidak dapat melakukan impor relatif". Jadi, Anda harus mengikat nama sebelum memuatnya. Alasannya adalah invarian mendasar dari sistem impor relatif: "holding invarian adalah jika Anda memiliki sys.modules ['spam'] dan sys.modules ['spam.foo'] (seperti yang Anda lakukan setelah impor di atas ), yang terakhir harus muncul sebagai atribut foo dari mantan " seperti yang dibahas di sini .

12
Sam Grondahl

Untuk mengimpor modul Anda, Anda perlu menambahkan direktori ke variabel lingkungan, baik sementara atau permanen.

Untuk sementara

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

Secara permanen

Menambahkan baris berikut ke file .bashrc Anda (di linux) dan mengeksekusi source ~/.bashrc di terminal:

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

Kredit/Sumber: saarrrr , pertanyaan stackexchange lain

11
Miladiouss

Berikut adalah beberapa kode yang berfungsi di semua versi Python, dari 2.7-3.5 dan bahkan mungkin yang lain.

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

Saya mengujinya. Mungkin jelek tapi sejauh ini adalah satu-satunya yang berfungsi di semua versi.

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

Saya yakin Anda dapat menggunakan imp.find_module() dan imp.load_module() untuk memuat modul yang ditentukan. Anda harus memisahkan nama modul dari jalur, mis. Jika Anda ingin memuat /home/mypath/mymodule.py yang perlu Anda lakukan:

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

... tapi itu harus menyelesaikan pekerjaan.

8
Matt

Buat python module test.py

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

Buat modul python test_check.py

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

Kita dapat mengimpor modul yang diimpor dari modul.

3
abhimanyu

Anda dapat menggunakan modul pkgutil (khususnya metode walk_packages ) untuk mendapatkan daftar paket di direktori saat ini. Dari sana sepele untuk menggunakan mesin importlib untuk mengimpor modul yang Anda inginkan:

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

Ini seharusnya bekerja

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

Saya tidak mengatakan bahwa itu lebih baik, tetapi demi kelengkapan, saya ingin menyarankan fungsi exec , tersedia dalam python 2 dan 3. exec memungkinkan Anda untuk mengeksekusi kode arbitrer dalam lingkup global, atau dalam lingkup internal, disediakan sebagai kamus.

Misalnya, jika Anda memiliki modul yang disimpan di "/path/to/module "dengan fungsi foo(), Anda bisa menjalankannya dengan melakukan hal berikut:

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

Ini membuatnya sedikit lebih eksplisit bahwa Anda memuat kode secara dinamis, dan memberi Anda kekuatan tambahan, seperti kemampuan untuk menyediakan builtin khusus.

Dan jika memiliki akses melalui atribut, alih-alih kunci penting bagi Anda, Anda dapat mendesain kelas dict khusus untuk global, yang menyediakan akses seperti itu, mis .:

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

Area Python 3.4 ini tampaknya sangat berliku untuk dipahami! Namun dengan sedikit peretasan menggunakan kode dari Chris Calloway sebagai permulaan saya berhasil membuat sesuatu bekerja. Inilah fungsi dasarnya.

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

Ini tampaknya menggunakan modul yang tidak usang dari Python 3.4. Saya tidak berpura-pura mengerti mengapa, tetapi tampaknya berhasil dari dalam suatu program. Saya menemukan solusi Chris bekerja pada baris perintah tetapi tidak dari dalam suatu program.

3
Redlegjed

Untuk mengimpor modul dari nama file yang diberikan, Anda dapat memperpanjang sementara jalur, dan mengembalikan jalur sistem di akhirnya blok referensi:

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

Impor modul paket saat runtime (resep Python)

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

Di Linux, menambahkan tautan simbolis di direktori skrip python Anda berfungsi.

yaitu:

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

python akan membuat /absolute/path/to/script/module.pyc dan akan memperbaruinya jika Anda mengubah konten /absolute/path/to/module/module.py

kemudian sertakan yang berikut ini di mypythonscript.py

from module import *
2
user2760152

Saya membuat paket yang menggunakan imp untuk Anda. Saya menyebutnya import_file dan beginilah caranya digunakan:

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

Anda bisa mendapatkannya di:

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

atau di

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

2
ubershmekel

caranya cukup sederhana: misalkan Anda ingin mengimpor file dengan path relatif ../../MyLibs/pyfunc.py


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

Tetapi jika Anda berhasil tanpa penjaga Anda akhirnya bisa mendapatkan jalan yang sangat panjang

1
Andrei Keino

Sebuah solusi sederhana menggunakan importlib alih-alih paket imp (diuji untuk Python 2.7, meskipun harus juga berfungsi untuk 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")

Sekarang Anda dapat langsung menggunakan namespace dari modul yang diimpor, seperti ini:

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

Keuntungan dari solusi ini adalah bahwa kita bahkan tidak perlu tahu nama sebenarnya dari modul yang ingin kita impor , untuk menggunakannya dalam kode kita. Ini berguna, mis. jika jalur modul adalah argumen yang dapat dikonfigurasi.

1
Ataxias

Menambahkan ini ke daftar jawaban karena saya tidak dapat menemukan apa pun yang berfungsi. Ini akan memungkinkan impor modul python dikompilasi (pyd) di 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

Jawaban ini adalah tambahan untuk jawaban Sebastian Rittau menanggapi komentar: "tetapi bagaimana jika Anda tidak memiliki nama modul?" Ini adalah cara cepat dan kotor untuk mendapatkan kemungkinan nama modul python diberi nama file - itu hanya naik pohon sampai menemukan direktori tanpa file __init__.py dan kemudian mengubahnya kembali menjadi nama file. Untuk Python 3.4+ (menggunakan pathlib), yang masuk akal karena orang Py2 dapat menggunakan "imp" atau cara lain untuk melakukan impor relatif:

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

Tentunya ada kemungkinan untuk peningkatan, dan file __init__.py opsional mungkin memerlukan perubahan lain, tetapi jika Anda memiliki __init__.py secara umum, ini bisa dilakukan.