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.
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.
Câu trả lời:
Đố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 .
__import__
.
imp.load_source
chỉ đặt .__name__
mô-đun trả về. nó không có hiệu lực tải.
imp.load_source()
xác định khóa của mục nhập mới được tạo trong sys.modules
từ điển, vì vậy đối số đầu tiên thực sự ảnh hưởng đến việc tải.
imp
mô-đun bị phản đối kể từ phiên bản 3.4: Các imp
gói đang chờ deprecation ủng hộ importlib
.
Ư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
sys.path.append
để trỏ đến một tập tin python duy nhất thay vì một thư mục?
importlib.import_module(mod_name)
có thể được sử dụng thay vì nhập rõ ràng ở đây nếu tên mô-đun không được biết đến trong thời gian chạy sys.path.pop()
, tuy nhiên, tôi sẽ thêm một mã nhập vào không cố gắng nhập thêm các mô-đun khi nó được sử dụng.
Nếu mô-đun cấp cao nhất của bạn không phải là 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ẽ thực hiện 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 .
mymodule
gì
/path/to/your/module/
có thật /path/to/your/PACKAGE/
không? và mymodule
ý bạn là myfile.py
gì?
Để 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.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Thêm dòng sau vào .bashrc
tệp 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
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 có 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 tiêu 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+
result[name]
, result.get('name', default_value)
, vv)
from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
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
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')
except:
mệnh đề Catch-all hiếm khi là một ý tưởng tốt.
save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
this is already addressed by the standard library
yeah, nhưng python có thói quen khó chịu là không tương thích ngược ... vì câu trả lời được kiểm tra cho biết có 2 cách khác nhau trước và sau 3.3. Trong trường hợp đó, tôi muốn viết chức năng phổ quát của riêng mình hơn là kiểm tra phiên bản nhanh chóng. Và vâng, có thể mã này không được bảo vệ quá tốt, nhưng nó cho thấy một ý tưởng (đó là os.chdir (), tôi chưa hiểu về nó), dựa vào đó tôi có thể viết mã tốt hơn. Do đó +1.
Đâ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.
load_source
không nhập tập lệnh và cung cấp quyền truy cập tập lệnh vào các mô-đun và toàn cầu tại thời điểm nhập.
Tôi đã đưa ra một phiên bản sửa đổi nhỏ của câu trả lời tuyệt vời @ SebastianRittau (đố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 một cách rõ ràng SourceFileLoader
là máy móc sẽ không cố gắng tìm ra loại tệp từ phần mở rộng. Điều này có nghĩa là bạn có thể tải một cái gì đó như một .txt
tệp bằng phương pháp này, nhưng bạn không thể làm điều đó spec_from_file_location
mà không chỉ định trình tải vì .txt
không có trong importlib.machinery.SOURCE_SUFFIXES
.
Bạn có nghĩa là tải hoặc nhập khẩu?
Bạn có thể thao tác sys.path
danh sách 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
sys.path[0:0] = ['/foo']
Explicit is better than implicit.
Vậy tại sao không sys.path.insert(0, ...)
thay thế sys.path[0:0]
?
Tôi tin rằng bạn có thể sử dụng imp.find_module()
và imp.load_module()
để tải các mô-đun được 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 phải làm:
imp.find_module('mymodule', '/home/mypath/')
... nhưng điều đó sẽ hoàn thành công việc.
Bạn có thể sử dụng pkgutil
mô-đun (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 importlib
máy móc để 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!
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.
Khu vực này của Python 3,4 dường như cực kỳ khó hiểu! Tuy nhiên, với một chút hack bằng cách sử dụng mã từ Chris Calloway khi bắt đầu, tôi đã xoay sở để có được thứ gì đó hoạt động. Đâ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.
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 exec
chức năng, 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 phạm vi nội bộ, 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 làm 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)
Để nhập mô-đun từ mộ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 tham chiếu khối cuối cùng :
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
Đ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)
name, ext = os.path.splitext(os.path.basename(infile))
. Phương pháp của bạn hoạt động vì hạn chế trước đó đối với phần mở rộng .py. Ngoài ra, có lẽ bạn nên nhập mô-đun vào một số mục từ điển / biến.
Nếu chúng ta có các tập lệnh trong cùng một dự án nhưng trong các thư mục khác nhau, chúng ta có thể giải quyết vấn đề này bằng phương pháp sau.
Trong tình huống utils.py
này là trongsrc/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
Tôi đã thực hiện một gói sử dụng imp
cho bạn. Tôi gọi nó 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
Nhập mô-đun gói trong thời gian 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)
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
trăn sẽ tạo ra /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 *
git
và kiểm tra git status
để xác minh rằng các thay đổi của bạn đối với tập lệnh thực sự khiến nó trở lại tài liệu nguồn và không bị mất trong ether.
Tôi đã viết chức năng nhập toàn cầu và di động của riêng mình, dựa trên importlib
mô-đun, cho:
sys.path
hoặc lưu trữ đường dẫn tìm kiếm.Cấu trúc thư mục ví dụ:
<root>
|
+- test.py
|
+- testlib.py
|
+- /std1
| |
| +- testlib.std1.py
|
+- /std2
| |
| +- testlib.std2.py
|
+- /std3
|
+- testlib.std3.py
Phụ thuộc và trật tự bao gồm:
test.py
-> testlib.py
-> testlib.std1.py
-> testlib.std2.py
-> testlib.std3.py
Thực hiện:
Cửa hàng thay đổi mới nhất: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py
kiểm tra :
import os, sys, inspect, copy
SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("test::SOURCE_FILE: ", SOURCE_FILE)
# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl
tkl.tkl_init(tkl)
# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()
tkl_import_module(SOURCE_DIR, 'testlib.py')
print(globals().keys())
testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test() # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test() # ... but reachable through the `globals` + `getattr`
tkl_import_module(SOURCE_DIR, 'testlib.py', '.')
print(globals().keys())
base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test() # does not reachable directly ...
globals()['testlib.std3'].std3_test() # ... but reachable through the `globals` + `getattr`
testlib.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')
# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')
print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)
def base_test():
print('base_test')
testlib.std1.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)
tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')
def std1_test():
print('std1_test')
testlib.std2.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)
def std2_test():
print('std2_test')
testlib.std3.py :
# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)
print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)
def std3_test():
print('std3_test')
Đầu ra ( 3.7.4
):
test::SOURCE_FILE: <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE: <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE: <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE: <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE: <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test
Đã thử nghiệm trên Python 3.7.4
, 3.2.5
.2.7.16
Ưu :
testlib.std.py
như testlib
, testlib.blabla.py
nhưtestlib_blabla
, v.v.).sys.path
hoặc vào một lưu trữ đường dẫn tìm kiếm.SOURCE_FILE
và SOURCE_DIR
giữa các lệnh gọi đếntkl_import_module
.3.4.x
và cao hơn] Có thể trộn các không gian tên mô-đun trong các tkl_import_module
cuộc gọi lồng nhau (ví dụ: named->local->named
hoặclocal->named->local
vv).3.4.x
và cao hơn] Có thể tự động xuất các biến / hàm / lớp toàn cầu từ nơi được khai báo cho tất cả các mô đun con được nhập thông qua tkl_import_module
(thông qua tkl_declare_global
hàm).Nhược điểm :
3.3.x
và thấp hơn] Yêu cầu khai báo tkl_import_module
trong tất cả các mô-đun gọi tkl_import_module
(sao chép mã)Cập nhật 1,2 (chỉ dành cho 3.4.x
và cao hơn):
Trong Python 3.4 trở lên, bạn có thể bỏ qua yêu cầu khai báo tkl_import_module
trong mỗi mô-đun bằng cách khai báo tkl_import_module
trong mô-đun cấp cao nhất và hàm sẽ tự tiêm cho tất cả các mô-đun con trong một cuộc gọi (đó là một kiểu nhập tự triển khai).
Cập nhật 3 :
Đã thêm chức năng tkl_source_module
tương tự như bash source
với bảo vệ thực thi hỗ trợ khi nhập (được thực hiện thông qua hợp nhất mô-đun thay vì nhập).
Cập nhật 4 :
Đã thêm chức năng tkl_declare_global
để tự động xuất một biến toàn cục mô-đun cho tất cả các mô-đun con trong đó biến toàn cục mô-đun không hiển thị vì không phải là một phần của mô-đun con.
Cập nhật 5 :
Tất cả các chức năng đã được chuyển vào thư viện tacklelib, xem liên kết ở trên.
Có một gói dành riêng cho việc này cụ thể:
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')
Nó đã được thử nghiệm trên các phiên bản Python (Jython và PyPy), nhưng nó có thể quá mức tùy thuộc vào quy mô dự án của bạn.
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()
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
Một giải pháp đơn giản sử dụng importlib
thay vì imp
gói (đã 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 rất hữu ích, ví dụ trong trường hợp đường dẫn của mô-đun là một đối số có thể định cấu hình.
sys.path
, không phù hợp với mọi trường hợp sử dụng.
sys.path.pop()
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ó __init__.py
tệp 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ó khả năng cải tiến và các __init__.py
tệp tùy chọn có thể cần các thay đổi khác, nhưng nếu bạn __init__.py
nói chung, đây là mẹo.
Cách tốt nhất, tôi nghĩ là từ tài liệu chính thức ( 29.1. Imp - Truy cập nội bộ nhập khẩu ):
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()