Est-ce que quelqu'un pourrait me fournir un bon moyen d'importer tout un répertoire de modules?
J'ai une structure comme celle-ci:
/Foo
bar.py
spam.py
eggs.py
J'ai simplement essayé de le convertir en paquet en ajoutant __init__.py
et en faisant from Foo import *
, mais cela n'a pas fonctionné comme je l'avais espéré.
Répertorie tous les fichiers python (.py
) du dossier en cours et mettez-les en tant que variable __all__
dans __init__.py
from os.path import dirname, basename, isfile, join
import glob
modules = glob.glob(join(dirname(__file__), "*.py"))
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
Ajoutez la variable __all__
à la variable __init__.py
contenant:
__all__ = ["bar", "spam", "eggs"]
Voir aussi http://docs.python.org/tutorial/modules.html
Mise à jour: Aujourd'hui, vous voudrez probablement utiliser importlib
à la place.
Transformez le répertoire Foo en un package en ajoutant un __init__.py
. Dans ce __init__.py
ajouter:
import bar
import eggs
import spam
Puisque vous le voulez dynamique (ce qui peut ne pas être une bonne idée), listez tous les fichiers py avec list dir et importez-les avec quelque chose comme ça:
import os
for module in os.listdir(os.path.dirname(__file__)):
if module == '__init__.py' or module[-3:] != '.py':
continue
__import__(module[:-3], locals(), globals())
del module
Ensuite, à partir de votre code, faites ceci:
import Foo
Vous pouvez maintenant accéder aux modules avec
Foo.bar
Foo.eggs
Foo.spam
etc. from Foo import * n'est pas une bonne idée pour plusieurs raisons, y compris les conflits de noms et la difficulté d'analyser le code.
En développant la réponse de Mihail, je pense que la méthode la plus simple (comme dans le cas de ne pas gérer les chemins de fichiers directement) est la suivante:
__init__.py
vide sous Foo/
import pkgutil
import sys
def load_all_modules_from_dir(dirname):
for importer, package_name, _ in pkgutil.iter_modules([dirname]):
full_package_name = '%s.%s' % (dirname, package_name)
if full_package_name not in sys.modules:
module = importer.find_module(package_name
).load_module(full_package_name)
print module
load_all_modules_from_dir('Foo')
Tu auras:
<module 'Foo.bar' from '/home/.../Foo/bar.pyc'>
<module 'Foo.spam' from '/home/.../Foo/spam.pyc'>
Pour les débutants qui ne peuvent tout simplement pas le faire fonctionner et qui ont besoin de leurs mains.
Créez un dossier/home/el/foo et créez un fichier main.py
sous/home/el/foo Mettez ce code là:
from hellokitty import *
spam.spamfunc()
ham.hamfunc()
Faire un répertoire /home/el/foo/hellokitty
Créez un fichier __init__.py
sous /home/el/foo/hellokitty
et mettez-y le code:
__all__ = ["spam", "ham"]
Créez deux fichiers python: spam.py
et ham.py
sous /home/el/foo/hellokitty
Définir une fonction dans spam.py:
def spamfunc():
print "Spammity spam"
Définir une fonction dans ham.py:
def hamfunc():
print "Upgrade from baloney"
Exécuter:
el@apollo:/home/el/foo$ python main.py
spammity spam
Upgrade from baloney
Je me suis fatigué de ce problème moi-même, alors j'ai écrit un paquetage appelé automodinit pour y remédier. Vous pouvez l'obtenir de http://pypi.python.org/pypi/automodinit/ .
L'utilisation est comme ça:
automodinit
dans vos dépendances setup.py
.__ all__ = ["Je vais me réécrire"] # Ne modifiez pas la ligne ci-dessus, ni cette ligne! import automodinit automodinit.automodinit (__ name__ , __file__, globals ()) de l'automodinit # Tout ce que vous voulez peut aller après, il ne sera pas modifié.
C'est ça! À partir de maintenant, l'importation d'un module définira __all__ sur une liste de fichiers .py [co] du module et importera également chacun de ces fichiers comme si vous aviez tapé:
for x in __all__: import x
Par conséquent, l'effet de "from M import *" correspond exactement à "import M".
automodinit
est content de courir à l'intérieur des archives Zip et est donc sûr pour Zip.
Niall
Je sais que je suis en train de mettre à jour un article assez ancien et que j'ai essayé d'utiliser automodinit
, mais que le processus de configuration a été interrompu pour python3. Donc, sur la base de la réponse de Luca, j'ai proposé une réponse plus simple à ce problème - qui pourrait ne pas fonctionner avec .Zip -, donc j'ai pensé que je devrais la partager ici:
dans le module __init__.py
de yourpackage
:
#!/usr/bin/env python
import os, pkgutil
__all__ = list(module for _, module, _ in pkgutil.iter_modules([os.path.dirname(__file__)]))
et dans un autre paquet ci-dessous yourpackage
:
from yourpackage import *
Ensuite, tous les modules placés dans le package seront chargés et, si vous écrivez un nouveau module, il sera également importé automatiquement. Bien sûr, utiliser ce genre de choses avec précaution, avec de grands pouvoirs entraîne de grandes responsabilités.
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
__import__(module)
J'ai aussi rencontré ce problème et c'était ma solution:
import os
def loadImports(path):
files = os.listdir(path)
imps = []
for i in range(len(files)):
name = files[i].split('.')
if len(name) > 1:
if name[1] == 'py' and name[0] != '__init__':
name = name[0]
imps.append(name)
file = open(path+'__init__.py','w')
toWrite = '__all__ = '+str(imps)
file.write(toWrite)
file.close()
Cette fonction crée un fichier (dans le dossier fourni) nommé __init__.py
, qui contient une variable __all__
contenant chaque module du dossier.
Par exemple, j'ai un dossier nommé Test
qui contient:
Foo.py
Bar.py
Donc, dans le script, je veux que les modules soient importés, je vais écrire:
loadImports('Test/')
from Test import *
Ceci importera tout de Test
et le fichier __init__.py
dans Test
contiendra maintenant:
__all__ = ['Foo','Bar']
Exemple d'Anurag avec quelques corrections:
import os, glob
modules = glob.glob(os.path.join(os.path.dirname(__file__), "*.py"))
__all__ = [os.path.basename(f)[:-3] for f in modules if not f.endswith("__init__.py")]
Anurag Uniyal answer avec les améliorations suggérées!
#!/usr/bin/python
# -*- encoding: utf-8 -*-
import os
import glob
all_list = list()
for f in glob.glob(os.path.dirname(__file__)+"/*.py"):
if os.path.isfile(f) and not os.path.basename(f).startswith('_'):
all_list.append(os.path.basename(f)[:-3])
__all__ = all_list
C'est le meilleur moyen que j'ai trouvé jusqu'à présent:
from os.path import dirname, join, isdir, abspath, basename
from glob import glob
pwd = dirname(__file__)
for x in glob(join(pwd, '*.py')):
if not x.startswith('__'):
__import__(basename(x)[:-3], globals(), locals())
Voir que votre __init__.py
définit __all__
. Le modules - packages doc dit
Les fichiers
__init__.py
sont nécessaires pour que Python traite les répertoires comme contenant des packages; Ceci est fait pour empêcher les répertoires avec un nom commun, tel que string, de cacher par inadvertance des modules valides apparaissant plus tard sur le chemin de recherche de module. Dans le cas le plus simple,__init__.py
peut n'être qu'un fichier vide, mais il peut également exécuter le code d'initialisation du package ou définir la variable__all__
, décrite plus loin....
La seule solution consiste pour l'auteur du package à fournir un index explicite du package. L’instruction import utilise la convention suivante: si le code
__init__.py
d’un package définit une liste nommée__all__
, il s’agit de la liste des noms de modules à importer lorsqu’un importation de package * est détecté. Il appartient à l'auteur du paquet de tenir cette liste à jour lorsqu'une nouvelle version du paquet est publiée. Les auteurs de paquet peuvent également décider de ne pas le supporter, s’ils ne voient aucune utilisation pour importer * à partir de leur paquet. Par exemple, le fichiersounds/effects/__init__.py
pourrait contenir le code suivant:
__all__ = ["echo", "surround", "reverse"]
Cela signifierait que
from sound.effects import *
importerait les trois sous-modules nommés du paquet de sons.
Regardez le module pkgutil de la bibliothèque standard. Cela vous permettra de faire exactement ce que vous voulez tant que vous avez un fichier __init__.py
dans le répertoire. Le fichier __init__.py
peut être vide.
J'ai créé un module pour cela, qui ne repose pas sur __init__.py
(ni aucun autre fichier auxiliaire) et me permet de ne taper que les deux lignes suivantes:
import importdir
importdir.do("Foo", globals())
N'hésitez pas à réutiliser ou à contribuer: http://gitlab.com/aurelien-lourot/importdir
Importez-les simplement par importlib et ajoutez-les à __all__
(l'action add
est facultative) dans récuring dans le __init__.py
du paquet.
/Foo
bar.py
spam.py
eggs.py
__init__.py
# __init__.py
import os
import importlib
pyfile_extes = ['py', ]
__all__ = [importlib.import_module('.%s' % filename, __package__) for filename in [os.path.splitext(i)[0] for i in os.listdir(os.path.dirname(__file__)) if os.path.splitext(i)[1] in pyfile_extes] if not filename.startswith('__')]
del os, importlib, pyfile_extes