web-dev-qa-db-fra.com

Comment charger tous les modules dans un dossier?

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é.

229
Evan Fosmark

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')]
352
Anurag Uniyal

Ajoutez la variable __all__ à la variable __init__.py contenant:

__all__ = ["bar", "spam", "eggs"]

Voir aussi http://docs.python.org/tutorial/modules.html

127
stefanw

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.

45
Lennart Regebro

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:

  1. créer un fichier __init__.py vide sous Foo/
  2. Execute
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'>
37
Luca Invernizzi

Python, incluez tous les fichiers dans un répertoire:

Pour les débutants qui ne peuvent tout simplement pas le faire fonctionner et qui ont besoin de leurs mains.

  1. 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()
    
  2. Faire un répertoire /home/el/foo/hellokitty

  3. Créez un fichier __init__.py sous /home/el/foo/hellokitty et mettez-y le code:

    __all__ = ["spam", "ham"]
    
  4. Créez deux fichiers python: spam.py et ham.py sous /home/el/foo/hellokitty

  5. Définir une fonction dans spam.py:

    def spamfunc():
      print "Spammity spam"
    
  6. Définir une fonction dans ham.py:

    def hamfunc():
      print "Upgrade from baloney"
    
  7. Exécuter:

    el@apollo:/home/el/foo$ python main.py 
    spammity spam
    Upgrade from baloney
    
21
Eric Leschinski

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:

  1. Incluez le package automodinit dans vos dépendances setup.py.
  2. Remplacez tous les fichiers __init__.py comme ceci:
 __ 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

16
Niall Douglas

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.

9
zmo
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
for imp, module, ispackage in pkgutil.walk_packages(path=__path__, prefix=__name__+'.'):
  __import__(module)
6
Ricky

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']
5
Penguinblade

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")]
4
kzar

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  
4
Eduardo Lucio

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

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 fichier sounds/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.

3
gimel

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.

1
Mihail Mihaylov

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

1
Aurelien

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
0
Cheney