it-swarm-vi.tech

Làm thế nào để nhập một mô-đun cho đường dẫn đầy đủ?

Làm cách nào tôi có thể tải mô-đun Python với đường dẫn đầy đủ của nó? Lưu ý rằng tệp có thể ở bất kỳ đâu trong hệ thống tệp, vì đây là tùy chọn cấu hình.

922
derfred

Đối với Python 3.5+ sử dụng:

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

Đối với Python 3.3 và 3.4, hãy sử dụng:

from importlib.machinery import SourceFileLoader

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

(Mặc dù điều này đã không được chấp nhận trong Python 3.4.)

Đối với Python 2 sử dụng:

import imp

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

Có các hàm tiện lợi tương đương cho các tệp Python và DLL được biên dịch.

Xem thêm http://bugs.python.org/su21436 .

1055
Sebastian Rittau

Ưu điểm của việc thêm đường dẫn đến sys.path (sử dụng imp) là nó đơn giản hóa mọi thứ khi nhập nhiều hơn một mô-đun từ một gói. Ví dụ:

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

Bạn cũng có thể làm một cái gì đó như thế này và thêm thư mục mà tệp cấu hình đang ngồi vào đường dẫn tải Python, sau đó chỉ cần thực hiện nhập thông thường, giả sử bạn biết trước tên của tệp, trong trường hợp này là "config".

Lộn xộn, nhưng nó hoạt động.

configfile = '~/config.py'

import os
import sys

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

import config
19
ctcherry

Có vẻ như bạn không muốn nhập cụ thể tệp cấu hình (có rất nhiều tác dụng phụ và các biến chứng bổ sung liên quan), bạn chỉ muốn chạy nó và có thể truy cập vào không gian tên kết quả. Thư viện chuẩn cung cấp một API cụ thể cho dạng đó dưới dạng runpy.run_path :

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

Giao diện đó có sẵn trong Python 2.7 và Python 3.2+

19
ncoghlan

Bạn có thể dùng

load_source(module_name, path_to_file) 

phương thức từ mô-đun imp .

16
zuber

Tôi đã đưa ra một phiên bản sửa đổi nhỏ của @ SebastianRittau câu trả lời tuyệt vời (đối với Python> 3.4 tôi nghĩ), sẽ cho phép bạn tải một tệp với bất kỳ tiện ích mở rộng nào dưới dạng mô-đun bằng cách sử dụng spec_from_loader thay vì 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)

Ưu điểm của việc mã hóa đường dẫn trong một SourceFileLoader rõ ràng là máy móc sẽ không cố gắng tìm ra loại tệp từ tiện ích mở rộng. Điều này có nghĩa là bạn có thể tải một cái gì đó như tệp .txt bằng phương thức này, nhưng bạn không thể làm điều đó với spec_from_file_location mà không chỉ định trình tải vì .txt không nằm trong importlib.machinery.SOURCE_SUFFIXES .

13
Mad Physicist

Bạn có nghĩa là tải hoặc nhập khẩu?

Bạn có thể thao tác danh sách sys.path chỉ định đường dẫn đến mô-đun của bạn, sau đó nhập mô-đun của bạn. Ví dụ, được cung cấp một mô-đun tại:

/foo/bar.py

Bạn có thể làm:

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

Nếu mô-đun cấp cao nhất của bạn không phải là một tệp nhưng được đóng gói dưới dạng thư mục có __init__.py, thì giải pháp được chấp nhận gần như hoạt động, nhưng không hoàn toàn. Trong Python 3.5+, đoạn mã sau là cần thiết (lưu ý dòng được thêm bắt đầu bằng '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)

Nếu không có dòng này, khi exec_module được thực thi, nó sẽ cố gắng ràng buộc nhập khẩu tương đối ở cấp cao nhất của bạn __init__.py với tên mô-đun cấp cao nhất - trong trường hợp này là "mymodule". Nhưng "mymodule" chưa được tải nên bạn sẽ gặp lỗi "SystemError: Mô-đun mẹ 'mymodule' không được tải, không thể thực hiện nhập tương đối". Vì vậy, bạn cần phải ràng buộc tên trước khi bạn tải nó. Lý do cho điều này là bất biến cơ bản của hệ thống nhập tương đối: "Việc giữ bất biến là nếu bạn có sys.modules ['spam'] và sys.modules ['spam.foo'] (như bạn sẽ làm sau khi nhập ở trên ), cái sau phải xuất hiện dưới dạng thuộc tính foo của cái trước " như được thảo luận ở đây .

12
Sam Grondahl

Để nhập mô-đun của bạn, bạn cần thêm thư mục của nó vào biến môi trường, tạm thời hoặc vĩnh viễn.

Tạm thời

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

Vĩnh viễn

Thêm dòng sau vào tệp .bashrc của bạn (trong linux) và thực hiện source ~/.bashrc trong thiết bị đầu cuối:

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

Tín dụng/Nguồn: saarrrr , một câu hỏi stackexchange khác

11
Miladiouss

Đây là một số mã hoạt động trong tất cả các phiên bản Python, từ 2.7-3.5 và có thể cả những mã khác.

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

Tôi đã thử nó. Nó có thể xấu nhưng cho đến nay là người duy nhất hoạt động trong tất cả các phiên bản.

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

Tôi tin rằng bạn có thể sử dụng imp.find_module()imp.load_module() để tải mô-đun chỉ định. Bạn sẽ cần tách tên mô-đun khỏi đường dẫn, tức là nếu bạn muốn tải /home/mypath/mymodule.py bạn cần làm:

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

... nhưng điều đó sẽ hoàn thành công việc.

8
Matt

Tạo mô-đun python test.txt

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

Tạo mô-đun python test_check.py

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

Chúng ta có thể nhập mô-đun nhập từ mô-đun.

3
abhimanyu

Bạn có thể sử dụng mô-đun pkgutil (cụ thể là walk_packages phương thức) để lấy danh sách các gói trong thư mục hiện tại. Từ đó, việc sử dụng máy móc importlib để nhập các mô-đun bạn muốn là chuyện nhỏ:

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

Điều này sẽ làm việc

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

Tôi không nói rằng nó tốt hơn, nhưng để hoàn thiện, tôi muốn đề xuất hàm exec , có sẵn trong cả python 2 và 3. exec cho phép bạn thực thi mã tùy ý trong phạm vi toàn cầu, hoặc trong một phạm vi nội bộ, được cung cấp như một từ điển.

Ví dụ: nếu bạn có một mô-đun được lưu trữ trong "/path/to/module "với chức năng foo(), bạn có thể chạy nó bằng cách thực hiện như sau:

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

Điều này làm cho rõ ràng hơn một chút rằng bạn đang tải mã động và cấp cho bạn một số sức mạnh bổ sung, chẳng hạn như khả năng cung cấp nội dung tùy chỉnh.

Và nếu việc truy cập thông qua các thuộc tính, thay vì các khóa là quan trọng đối với bạn, bạn có thể thiết kế một lớp chính tả tùy chỉnh cho toàn cầu, cung cấp quyền truy cập đó, ví dụ:

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

Khu vực này của Python 3,4 dường như cực kỳ khó hiểu! Tuy nhiên. Đây là chức năng cơ bản.

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

Điều này dường như sử dụng các mô-đun không phản đối từ Python 3.4. Tôi không giả vờ hiểu tại sao, nhưng nó dường như hoạt động từ trong một chương trình. Tôi thấy giải pháp của Chris hoạt động trên dòng lệnh nhưng không phải từ bên trong một chương trình.

3
Redlegjed

Để nhập mô-đun từ tên tệp đã cho, bạn có thể tạm thời mở rộng đường dẫn và khôi phục đường dẫn hệ thống trong khối cuối cùng tham chiếu:

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

Nhập mô-đun gói khi chạy (công thức 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

Trong Linux, việc thêm một liên kết tượng trưng trong thư mục tập lệnh python của bạn được đặt.

i E:

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

python sẽ tạo /absolute/path/to/script/module.pyc và sẽ cập nhật nó nếu bạn thay đổi nội dung của /absolute/path/to/module/module.py

sau đó bao gồm các mục sau trong mypythonscript.py

from module import *
2
user2760152

Tôi đã tạo một gói sử dụng imp cho bạn. Tôi gọi nó là import_file và đây là cách nó được sử dụng:

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

Bạn có thể lấy nó tại:

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

hoặc tại

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

2
ubershmekel

cách khá đơn giản: giả sử bạn muốn nhập tệp với đường dẫn tương đối ../../MyLibs/pyfunc.py


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

Nhưng nếu bạn làm nó mà không có người bảo vệ, cuối cùng bạn cũng có thể đi được một con đường rất dài

1
Andrei Keino

Một giải pháp đơn giản sử dụng importlib thay vì gói imp (đã thử nghiệm cho Python 2.7, mặc dù nó cũng hoạt động với 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")

Bây giờ bạn có thể trực tiếp sử dụng không gian tên của mô-đun đã nhập, như thế này:

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

Ưu điểm của giải pháp này là chúng tôi thậm chí không cần biết tên thực của mô-đun mà chúng tôi muốn nhập , để sử dụng nó trong mã của mình. Điều này hữu ích, ví dụ: trong trường hợp đường dẫn của mô-đun là một đối số có thể cấu hình.

1
Ataxias

Thêm phần này vào danh sách các câu trả lời vì tôi không thể tìm thấy bất cứ điều gì hiệu quả. Điều này sẽ cho phép nhập các mô-đun python đã biên dịch (pyd) trong 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

Câu trả lời này là phần bổ sung cho câu trả lời của Sebastian Rittau khi trả lời bình luận: "nhưng nếu bạn không có tên mô-đun thì sao?" Đây là một cách nhanh chóng và bẩn thỉu để lấy tên mô-đun python có khả năng được đặt tên tệp - nó chỉ đi lên cây cho đến khi tìm thấy một thư mục không có tệp __init__.py và sau đó biến nó thành tên tệp. Đối với Python 3.4+ (sử dụng pathlib), điều này hợp lý vì người Py2 có thể sử dụng "imp" hoặc các cách khác để thực hiện nhập khẩu tương đối:

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

Chắc chắn có nhiều khả năng để cải thiện và các tệp __init__.py tùy chọn có thể cần các thay đổi khác, nhưng nếu bạn có __init__.py nói chung, thì đây là mẹo.

0