Jak zaimportować wszystkie moduły podrzędne?
Mam następującą strukturę katalogów:
| main.py
| scripts
|--| __init__.py
| script1.py
| script2.py
| script3.py
Z main.py
importowany jest moduł scripts
. Próbowałem używać pkgutils.walk_packages
w połączeniu z __all__
, ale używając tego, mogę importować wszystkie moduły bezpośrednio pod main
używając from scripts import *
. Chciałbym je wszystkie umieścić pod scripts
. Jaki byłby najczystszy sposób zaimportowania wszystkich podmodułów scripts
, abym mógł uzyskać dostęp scripts.script1
z main
?
EDIT: przepraszam, że byłem trochę niejasny. Chciałbym zaimportować podmoduły na run-time bez podania ich wprost w __init__.py
. Mogę użyć pkgutils.walk_packages
, aby uzyskać nazwy podmodułów (chyba, że ktoś zna lepszy sposób), ale nie jestem pewien najczystszego sposobu użycia tych nazw (a może Impiporterów, które walk_packages
zwraca?), aby je zaimportować.
9 answers
Edit: Oto jeden ze sposobów rekurencyjnego importowania wszystkiego w czasie wykonywania...
(Zawartość {[2] } w katalogu top package)
import pkgutil
__all__ = []
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
__all__.append(module_name)
module = loader.find_module(module_name).load_module(module_name)
globals()[module_name] = module
Nie używam tutaj __import__(__path__+'.'+module_name)
, ponieważ trudno jest poprawnie zaimportować za jego pomocą Pakiety. Jeśli nie masz zagnieżdżonych podpakietów i chcesz uniknąć używania globals()[module_name]
, jest to jeden ze sposobów, aby to zrobić.
Oryginalna odpowiedź (dla kontekstu, zignoruj othwerwise. Początkowo źle zrozumiałem pytanie):
Jak wygląda twój scripts/__init__.py
? Powinno być coś w stylu:
import script1
import script2
import script3
__all__ = ['script1', 'script2', 'script3']
Można nawet zrobić bez zdefiniowania __all__
, ale rzeczy (pydoc, jeśli nic innego) będą działać bardziej czysto, jeśli go zdefiniujesz, nawet jeśli jest to tylko lista tego, co zaimportowałeś.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-07 11:24:15
Jest to oparte na odpowiedzi, którą dostarczył kolypto, ale jego odpowiedź nie wykonuje rekurencyjnego importu pakietów, podczas gdy ta. Chociaż nie jest to wymagane przez główne pytanie, uważam, że import rekurencyjny ma zastosowanie i może być bardzo przydatny w wielu podobnych sytuacjach. Ja, na przykład, znalazłem to pytanie podczas wyszukiwania na ten temat.
Jest to przyjemny, czysty sposób na zaimportowanie modułów podpakietu, powinien być również przenośny i używa standardowego lib dla python 2.7+ / 3.x.
import importlib
import pkgutil
def import_submodules(package, recursive=True):
""" Import all submodules of a module, recursively, including subpackages
:param package: package (name or actual module)
:type package: str | module
:rtype: dict[str, types.ModuleType]
"""
if isinstance(package, str):
package = importlib.import_module(package)
results = {}
for loader, name, is_pkg in pkgutil.walk_packages(package.__path__):
full_name = package.__name__ + '.' + name
results[full_name] = importlib.import_module(full_name)
if recursive and is_pkg:
results.update(import_submodules(full_name))
return results
Użycie:
# from main.py, as per the OP's project structure
import scripts
import_submodules(scripts)
# Alternatively, from scripts.__init__.py
import_submodules(__name__)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:20
Po prostu działa i umożliwia względny import wewnątrz pakietów:
def import_submodules(package_name):
""" Import all submodules of a module, recursively
:param package_name: Package name
:type package_name: str
:rtype: dict[types.ModuleType]
"""
package = sys.modules[package_name]
return {
name: importlib.import_module(package_name + '.' + name)
for loader, name, is_pkg in pkgutil.walk_packages(package.__path__)
}
Użycie:
__all__ = import_submodules(__name__).keys()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-01 15:03:59
Nie tak czysto, jak bym chciała, ale żadna z czystszych metod nie zadziałała. Uzyskuje się w ten sposób określone zachowanie:
Struktura katalogu:
| pkg
|--| __init__.py
| main.py
| scripts
|--| __init__.py
| script1.py
| script2.py
| script3.py
Gdzie pkg/scripts/__init__.py
jest puste, a pkg/__init__.py
zawiera:
import importlib as _importlib
import pkgutil as _pkgutil
__all__ = [_mod[1].split(".")[-1] for _mod in
filter(lambda _mod: _mod[1].count(".") == 1 and not
_mod[2] and __name__ in _mod[1],
[_mod for _mod in _pkgutil.walk_packages("." + __name__)])]
__sub_mods__ = [".".join(_mod[1].split(".")[1:]) for _mod in
filter(lambda _mod: _mod[1].count(".") > 1 and not
_mod[2] and __name__ in _mod[1],
[_mod for _mod in
_pkgutil.walk_packages("." + __name__)])]
from . import *
for _module in __sub_mods__:
_importlib.import_module("." + _module, package=__name__)
Chociaż jest brudny, powinien być przenośny. Użyłem tego kodu dla kilku różnych pakietów.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-10 17:46:41
Sam miałem dość tego problemu, więc napisałem pakiet o nazwie automodinit, aby go naprawić. Możesz go pobrać z http://pypi.python.org/pypi/automodinit / . użycie wygląda tak:
- Dołącz pakiet automodinit do swoich zależności
setup.py
. - Dodaj następujący tekst na początku pliku
__init__.py
:
__all__ = ["I will get rewritten"]
# Don't modify the line above, or this line!
import automodinit
automodinit.automodinit(__name__, __file__, globals())
del automodinit
# Anything else you want can go after here, it won't get modified.
To jest to! Od teraz importowanie modułu ustawia __all__
na
listę plików. py [co] w module, a także zaimportuje każdy
z tych pliki tak jakbyś wpisał:
for x in __all__: import x
Dlatego efekt from M import *
pasuje dokładnie import M
.
Automodinit jest zadowolony z działania z archiwów ZIP i dlatego jest bezpieczny dla ZIP.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-28 20:31:58
Pisałem małą bibliotekę osobistą i cały czas dodawałem nowe moduły, więc napisałem skrypt powłoki, aby szukać skryptów i tworzyć __init__.py
' s. skrypt jest uruchamiany tuż poza głównym katalogiem mojego pakietu, pylux.
Wiem, że prawdopodobnie nie jest to odpowiedź, której szukasz, ale to servered swój cel dla mnie i może być przydatna dla kogoś innego, zbyt.
#!/bin/bash
echo 'Traversing folder hierarchy...'
CWD=`pwd`
for directory in `find pylux -type d -exec echo {} \;`;
do
cd $directory
#echo Entering $directory
echo -n "" > __init__.py
for subdirectory in `find . -type d -maxdepth 1 -mindepth 1`;
do
subdirectory=`echo $subdirectory | cut -b 3-`
#echo -n ' ' ...$subdirectory
#echo -e '\t->\t' import $subdirectory
echo import $subdirectory >> __init__.py
done
for pyfile in *.py ;
do
if [ $pyfile = $(echo __init__.py) ]; then
continue
fi
#echo -n ' ' ...$pyfile
#echo -e '\t->\t' import `echo $pyfile | cut -d . -f 1`
echo import `echo $pyfile | cut -d . -f 1` >> __init__.py
done
cd $CWD
done
for directory in `find pylux -type d -exec echo {} \;`;
do
echo $directory/__init__.py:
cat $directory/__init__.py | awk '{ print "\t"$0 }'
done
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-29 18:59:18
Bawiłem się odpowiedzią Joe Kingtona i zbudowałem rozwiązanie, które wykorzystuje globals
i get/setattr
, a więc nie potrzebuje evalu. Drobna modyfikacja polega na tym, że zamiast bezpośrednio używać packages __path__
dla walk_packages
, używam katalogu nadrzędnego packages, a następnie importuję tylko Moduły zaczynające się od __name__ + "."
. Zostało to zrobione, aby niezawodnie pobrać wszystkie podpakiety z walk_packages
- w moim przypadku użycia miałem podpakiet o nazwie test
, który spowodował, że pkgutil iterował nad test
pakietem z Pythona biblioteka; ponadto użycie __path__
nie spowoduje rekurencji do podkatalogów packages. Wszystkie te problemy zostały zaobserwowane przy użyciu jython i python2. 5, poniższy kod jest testowany tylko w jython do tej pory.
Zauważ również, że pytanie OPs mówi tylko o importowaniu wszystkich modułów z pakietu, ten kod rekurencyjnie importuje również wszystkie pakiety.
from pkgutil import walk_packages
from os import path
__all__ = []
__pkg_prefix = "%s." % __name__
__pkg_path = path.abspath(__path__[0]).rsplit("/", 1)[0] #parent directory
for loader, modname, _ in walk_packages([__pkg_path]):
if modname.startswith(__pkg_prefix):
#load the module / package
module = loader.find_module(modname).load_module(modname)
modname = modname[len(__pkg_prefix):] #strip package prefix from name
#append all toplevel modules and packages to __all__
if not "." in modname:
__all__.append(modname)
globals()[modname] = module
#set everything else as an attribute of their parent package
else:
#get the toplevel package from globals()
pkg_name, rest = modname.split(".", 1)
pkg = globals()[pkg_name]
#recursively get the modules parent package via getattr
while "." in rest:
subpkg, rest = rest.split(".", 1)
pkg = getattr(pkg, subpkg)
#set the module (or package) as an attribute of its parent package
setattr(pkg, rest, module)
Jako przyszłe ulepszenie postaram się wprowadzić tę dynamikę za pomocą __getattr__
Hooka na pakiecie, więc rzeczywiste moduły są tylko importowane, gdy są dostępne...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:23
To działa mi ładnie w Pythonie 3.3. Zauważ, że działa to tylko dla podmoduł, które znajdują się w plikach w tym samym katalogu co __init__.py
. Z pewną pracą można go jednak ulepszyć do obsługi podmoduł w katalogach.
from glob import iglob
from os.path import basename, relpath, sep, splitext
def import_submodules(__path__to_here):
"""Imports all submodules.
Import this function in __init__.py and put this line to it:
__all__ = import_submodules(__path__)"""
result = []
for smfile in iglob(relpath(__path__to_here[0]) + "/*.py"):
submodule = splitext(basename(smfile))[0]
importstr = ".".join(smfile.split(sep)[:-1])
if not submodule.startswith("_"):
__import__(importstr + "." + submodule)
result.append(submodule)
return result
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-02 06:47:24
W Pythonie 3, możesz umieścić następujący kod w pliku scripts.__init__.py
:
import os
import os.path as op
__all__ = [
op.splitext(f)[0] # remove .py extension
for f in os.listdir(BASE_DIR) # list contents of current dir
if not f.startswith('_') and
((op.isfile(op.join(BASE_DIR, f)) and f.endswith('.py')) or
(op.isdir(op.join(BASE_DIR, f)) and op.isfile(op.join(BASE_DIR, f, '__init__.py'))))
]
from . import * # to make `scripts.script1` work after `import script`
Aby uzyskać więcej informacji na temat importu Pythona, polecam wystąpienie Davida Beazleya na PyCon 2015: https://youtu.be/0oTh1CXRaQ0
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-08 20:06:24