Jak mogę załadować moduł Python, mając pełną ścieżkę? Pamiętaj, że plik może znajdować się w dowolnym miejscu w systemie plików, ponieważ jest to opcja konfiguracji.
Jak mogę załadować moduł Python, mając pełną ścieżkę? Pamiętaj, że plik może znajdować się w dowolnym miejscu w systemie plików, ponieważ jest to opcja konfiguracji.
Odpowiedzi:
W przypadku języka 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()
W przypadku Python 3.3 i 3.4 użyj:
from importlib.machinery import SourceFileLoader
foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()
(Chociaż zostało to przestarzałe w Pythonie 3.4.)
W przypadku Python 2 użyj:
import imp
foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()
Istnieją równoważne funkcje wygody dla skompilowanych plików i bibliotek DLL Pythona.
Zobacz także http://bugs.python.org/issue21436 .
__import__
.
imp.load_source
ustawia tylko .__name__
wartość zwracanego modułu. nie wpływa na ładowanie.
imp.load_source()
określa klucz nowego wpisu utworzonego w sys.modules
słowniku, więc pierwszy argument rzeczywiście wpływa na ładowanie.
imp
Moduł jest nieaktualna od wersji 3.4: imp
Pakiet czeka Wycofanie na korzyść importlib
.
Zaletą dodania ścieżki do sys.path (w porównaniu z impem) jest to, że upraszcza to rzeczy podczas importowania więcej niż jednego modułu z jednego pakietu. Na przykład:
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
do wskazywania pojedynczego pliku python zamiast katalogu?
importlib.import_module(mod_name)
może być użyty zamiast jawnego importu tutaj, jeśli nazwa modułu nie jest znana w czasie wykonywania, dodałbym jednak sys.path.pop()
na końcu, zakładając, że importowany kod nie próbuje zaimportować większej liczby modułów, ponieważ jest używany.
Jeśli moduł najwyższego poziomu nie jest plikiem, ale jest spakowany jako katalog z __init__.py, wówczas zaakceptowane rozwiązanie prawie działa, ale nie całkiem. W Python 3.5+ potrzebny jest następujący kod (zwróć uwagę na dodany wiersz rozpoczynający się od „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 tego wiersza, gdy wykonywany jest moduł exec_module, próbuje on powiązać import względny z twojego najwyższego poziomu __init__.py z nazwą modułu najwyższego poziomu - w tym przypadku „mymodule”. Ale „mymoduł” nie jest jeszcze załadowany, więc pojawi się błąd „SystemError: Moduł macierzysty„ mymoduł ”nie został załadowany, nie może wykonać importu względnego”. Musisz więc powiązać nazwę przed załadowaniem. Powodem tego jest podstawowy niezmiennik względnego systemu importu: „Niezmiennym wstrzymaniem jest to, że jeśli masz sys.modules ['spam'] i sys.modules ['spam.foo'] (tak jak po powyższym imporcie ), ten drugi musi występować jako atrybut foo pierwszego ”, jak omówiono tutaj .
mymodule
?
/path/to/your/module/
jest właściwie /path/to/your/PACKAGE/
? a mymodule
masz na myśli myfile.py
?
Aby zaimportować moduł, musisz dodać jego katalog do zmiennej środowiskowej, tymczasowo lub na stałe.
import sys
sys.path.append("/path/to/my/modules/")
import my_module
Dodanie następującego wiersza do .bashrc
pliku (w systemie Linux) i wykonanie source ~/.bashrc
w terminalu:
export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"
Źródło / Źródło: saarrrr , kolejne pytanie dotyczące wymiany stosów
Wygląda na to, że nie chcesz specjalnie importować pliku konfiguracyjnego (który ma wiele skutków ubocznych i dodatkowych komplikacji), po prostu chcesz go uruchomić i mieć dostęp do wynikowej przestrzeni nazw. Biblioteka standardowa udostępnia interfejs API specjalnie w tym celu w postaci runpy.run_path :
from runpy import run_path
settings = run_path("/path/to/file.py")
Ten interfejs jest dostępny w Python 2.7 i Python 3.2+
result[name]
, result.get('name', default_value)
itp)
from runpy import run_path; from argparse import Namespace; mod = Namespace(**run_path('path/to/file.py'))
Możesz także zrobić coś takiego i dodać katalog, w którym znajduje się plik konfiguracyjny, do ścieżki ładowania Pythona, a następnie po prostu wykonać normalny import, zakładając, że znasz wcześniej nazwę pliku, w tym przypadku „config”.
Bałagan, ale działa.
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:
klauzuli catch-all rzadko jest dobrym pomysłem.
save_cwd = os.getcwd()
try: …
finally: os.chdir(save_cwd)
this is already addressed by the standard library
tak, ale python ma nieprzyjemny zwyczaj nie być kompatybilny wstecz ... ponieważ sprawdzona odpowiedź mówi, że istnieją 2 różne sposoby przed i po 3.3. W takim przypadku wolałbym napisać własną funkcję uniwersalną niż sprawdzić wersję w locie. I tak, może ten kod nie jest zbyt dobrze chroniony przed błędami, ale pokazuje pomysł (którym jest os.chdir (), o czym nie myślałem), na podstawie którego mogę napisać lepszy kod. Stąd +1.
Oto kod, który działa we wszystkich wersjach Pythona, od 2.7-3.5 i prawdopodobnie nawet w innych.
config_file = "/tmp/config.py"
with open(config_file) as f:
code = compile(f.read(), config_file, 'exec')
exec(code, globals(), locals())
Przetestowałem to. Może to być brzydkie, ale jak dotąd jest to jedyny, który działa we wszystkich wersjach.
load_source
nie, ponieważ importuje skrypt i zapewnia skryptowi dostęp do modułów i globałów podczas importowania.
Wymyśliłem nieco zmodyfikowaną wersję cudownej odpowiedzi @ SebastianRittau (myślę, że dla Pythona> 3.4), która pozwoli ci załadować plik z dowolnym rozszerzeniem jako moduł używający spec_from_loader
zamiast 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)
Zaletą jawnego kodowania ścieżki jest SourceFileLoader
to, że maszyneria nie będzie próbowała ustalić typu pliku z rozszerzenia. Oznacza to, że .txt
za pomocą tej metody można załadować plik podobny do pliku, ale nie można tego zrobić spec_from_file_location
bez określenia modułu ładującego, ponieważ .txt
nie ma go w katalogu importlib.machinery.SOURCE_SUFFIXES
.
Masz na myśli ładowanie czy importowanie?
Możesz manipulować sys.path
listą, określić ścieżkę do modułu, a następnie zaimportować moduł. Na przykład, biorąc pod uwagę moduł w:
/foo/bar.py
Mógłbyś:
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.
Dlaczego więc nie sys.path.insert(0, ...)
zamiast sys.path[0:0]
?
Wierzę, że możesz użyć imp.find_module()
i imp.load_module()
załadować określony moduł. Musisz podzielić nazwę modułu ze ścieżki, tzn. Jeśli chcesz załadować /home/mypath/mymodule.py
, musisz:
imp.find_module('mymodule', '/home/mypath/')
... ale to powinno załatwić sprawę.
Możesz użyć pkgutil
modułu (w szczególności walk_packages
metody), aby uzyskać listę pakietów w bieżącym katalogu. Stamtąd użycie importlib
maszyny do importowania wymaganych modułów jest banalne :
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!
Utwórz moduł python test.py
import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3
Utwórz moduł python test_check.py
from test import Client1
from test import Client2
from test import test3
Możemy zaimportować zaimportowany moduł z modułu.
Ten obszar Pythona 3.4 wydaje się niezwykle trudny do zrozumienia! Jednak przy odrobinie hakowania przy użyciu kodu Chrisa Calloway'a na początku udało mi się coś załatwić. Oto podstawowa funkcja.
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
Wygląda na to, że korzysta z nieaktualnych modułów z Python 3.4. Nie udaję, że rozumiem dlaczego, ale wydaje się, że działa z poziomu programu. Odkryłem, że rozwiązanie Chrisa działało w wierszu poleceń, ale nie w programie.
Nie twierdzę, że jest lepiej, ale ze względu na kompletność chciałem zasugerować exec
funkcję, dostępną zarówno w Pythonie 2, jak i 3.
exec
pozwala na wykonanie dowolnego kodu w zakresie globalnym lub wewnętrznym, dostarczone jako słownik.
Na przykład, jeśli masz moduł zapisany w "/path/to/module
„z funkcją” foo()
, możesz go uruchomić, wykonując następujące czynności:
module = dict()
with open("/path/to/module") as f:
exec(f.read(), module)
module['foo']()
To sprawia, że jest nieco bardziej wyraźne, że ładujesz kod dynamicznie i daje ci dodatkową moc, taką jak możliwość dostarczania niestandardowych wbudowanych funkcji.
A jeśli dostęp za pośrednictwem atrybutów, zamiast kluczy jest dla Ciebie ważny, możesz zaprojektować niestandardową klasę dict dla globałów, która zapewnia taki dostęp, np .:
class MyModuleClass(dict):
def __getattr__(self, name):
return self.__getitem__(name)
Aby zaimportować moduł z podanej nazwy pliku, możesz tymczasowo rozszerzyć ścieżkę i przywrócić ścieżkę systemową w odwołaniu do bloku na końcu :
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
To powinno działać
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))
. Ta metoda działa, ponieważ poprzednie ograniczenie rozszerzenia .py. Powinieneś również prawdopodobnie zaimportować moduł do jakiegoś wpisu zmiennej / słownika.
Jeśli mamy skrypty w tym samym projekcie, ale w innym katalogu, możemy rozwiązać ten problem, stosując następującą metodę.
W tej sytuacji utils.py
jestsrc/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
Zrobiłem imp
dla ciebie pakiet . Nazywam to import_file
i tak to się używa:
>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')
Możesz go uzyskać na:
http://pypi.python.org/pypi/import_file
lub o
Importuj moduły pakietów w czasie wykonywania (przepis na 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)
W Linuksie działa dodawanie dowiązania symbolicznego do katalogu, w którym znajduje się skrypt Pythona.
to znaczy:
ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py
Python utworzy /absolute/path/to/script/module.pyc
i zaktualizuje go, jeśli zmienisz zawartość/absolute/path/to/module/module.py
następnie dołącz następujące w mypythonscript.py
from module import *
git
i sprawdzając, git status
czy twoje zmiany w skrypcie faktycznie powodują powrót do dokumentu źródłowego i nie gubią się w eterze.
Napisałem własną globalną i przenośną funkcję importu opartą na importlib
module dla:
sys.path
lub od kiedykolwiek przechowywanej ścieżki wyszukiwania.Struktura katalogu przykładów:
<root>
|
+- test.py
|
+- testlib.py
|
+- /std1
| |
| +- testlib.std1.py
|
+- /std2
| |
| +- testlib.std2.py
|
+- /std3
|
+- testlib.std3.py
Zależność i porządek włączenia:
test.py
-> testlib.py
-> testlib.std1.py
-> testlib.std2.py
-> testlib.std3.py
Realizacja:
Sklep z najnowszymi zmianami: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py
test.py :
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')
Wyjście ( 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
Testowany w Pythonie 3.7.4
, 3.2.5
,2.7.16
Plusy :
testlib.std.py
as testlib
, testlib.blabla.py
as testlib_blabla
i tak dalej).sys.path
ani miejsca przechowywania ścieżki wyszukiwania.SOURCE_FILE
i SOURCE_DIR
między wywołaniami tkl_import_module
.3.4.x
i wyżej] Czy wymieszać nazw modułu w zagnieżdżonych tkl_import_module
połączeń (ex: named->local->named
albo local->named->local
i tak dalej).3.4.x
i wyżej] Może automatycznie eksportować zmienne globalne / funkcje / klasy, skąd są zadeklarowane do wszystkich modułów potomnych importowanych przez tkl_import_module
(poprzez tkl_declare_global
funkcję).Wady :
3.3.x
i niższych] Wymagaj deklarowania tkl_import_module
we wszystkich modułach, które wywołują tkl_import_module
(duplikacja kodu)Aktualizacja 1,2 (tylko dla wersji 3.4.x
wyższej i wyższej):
W Pythonie 3.4 i nowszych można ominąć wymóg deklarowania tkl_import_module
w każdym module przez deklarację tkl_import_module
w module najwyższego poziomu, a funkcja wstrzykiwałaby się do wszystkich modułów potomnych w jednym wywołaniu (jest to rodzaj importu samodzielnego wdrażania).
Aktualizacja 3 :
Dodano funkcję tkl_source_module
analogową do bash source
z ochroną wykonania wsparcia podczas importu (zaimplementowano poprzez scalenie modułu zamiast importu).
Aktualizacja 4 :
Dodano funkcję tkl_declare_global
automatycznego eksportowania globalnej zmiennej modułowej do wszystkich modułów potomnych, w których globalna zmienna modułowa nie jest widoczna, ponieważ nie jest częścią modułu potomnego.
Aktualizacja 5 :
Wszystkie funkcje zostały przeniesione do biblioteki tacklelib, patrz link powyżej.
Jest pakiet dedykowany do tego w szczególności:
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')
Jest testowany we wszystkich wersjach Pythona (również Jython i PyPy), ale może być nadmierną umiejętnością w zależności od wielkości projektu.
Dodanie tego do listy odpowiedzi, ponieważ nie mogłem znaleźć niczego, co działałoby. Umożliwi to import skompilowanych (pyd) modułów python w 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()
dość prosty sposób: załóżmy, że chcesz zaimportować plik ze ścieżką względną ../../MyLibs/pyfunc.py
libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf
Ale jeśli zdołasz przejść bez osłony, możesz w końcu uzyskać bardzo długą ścieżkę
Proste rozwiązanie wykorzystujące importlib
zamiast imp
pakietu (przetestowane dla Python 2.7, chociaż powinno również działać dla 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")
Teraz możesz bezpośrednio korzystać z przestrzeni nazw importowanego modułu, w następujący sposób:
a = module.myvar
b = module.myfunc(a)
Zaletą tego rozwiązania jest to , że nie musimy nawet znać rzeczywistej nazwy modułu, który chcielibyśmy zaimportować , aby użyć go w naszym kodzie. Jest to przydatne, np. W przypadku, gdy ścieżka modułu jest argumentem konfigurowalnym.
sys.path
, który nie pasuje do każdego przypadku użycia.
sys.path.pop()
Ta odpowiedź stanowi uzupełnienie odpowiedzi Sebastiana Rittau na komentarz: „ale co, jeśli nie masz nazwy modułu?” Jest to szybki i nieprzyzwoity sposób na uzyskanie prawdopodobnej nazwy modułu Pythona podając nazwę pliku - po prostu idzie w górę drzewa, dopóki nie znajdzie katalogu bez __init__.py
pliku, a następnie zamienia go z powrotem w nazwę pliku. W przypadku Python 3.4+ (używa pathlib), co ma sens, ponieważ ludzie Py2 mogą używać „imp” lub innych sposobów importowania względnego:
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))
Z pewnością istnieją możliwości ulepszenia, a opcjonalne __init__.py
pliki mogą wymagać innych zmian, ale jeśli tak __init__.py
, to załatwia sprawę.
Myślę, że najlepszym sposobem jest oficjalna dokumentacja ( 29.1. Imp - Dostęp do wewnętrznych elementów importu ):
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()