web-dev-qa-db-fra.com

Importation de classes à partir de différents fichiers dans un sous-répertoire

Voici la structure avec laquelle je travaille:

directory/
          script.py
          subdir/
                 __init__.py
                 myclass01.py
                 myclass02.py

Ce que je veux faire, c'est importer dans script.py les classes définies dans myclass01.py et myclass02.py. Si je fais:

from subdir.myclass01 import *

Cela fonctionne très bien pour la classe définie dans myclass01.py. Mais avec cette solution, s'il existe de nombreuses classes définies dans différents fichiers dans subdir et que je souhaite les importer toutes, je devrais taper une ligne pour chaque fichier. Il doit y avoir un raccourci pour cela. J'ai essayé:

from subdir.* import *

Mais ça n'a pas marché.

MODIFIER : voici le contenu des fichiers:

C'est __init__.py (en utilisant __all__ comme l'a suggéré Apalala):

__all__ = ['MyClass01','MyClass02']

C'est myclass01.py:

class MyClass01:
    def printsomething():
        print 'hey'

C'est myclass02.py:

class MyClass02:
    def printsomething():
        print 'sup'

C'est script.py:

from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()

Il s'agit de la trace que j'obtiens lorsque j'essaie d'exécuter script.py:

File "script.py", line 1, in <module>
    from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'
24
liewl

Bien que les noms utilisés ici soient différents de ceux affichés dans la structure de répertoire de votre question, vous pouvez utiliser ma réponse à la question intitulée Espaces de noms et classes . Le __init__.py Affiché ici aurait également permis au script usepackage.py D'être écrit de cette façon (package correspond à subdir dans votre question, et Class1 À myclass01, Etc.):

from package import *

print Class1
print Class2
print Class3

Révision (mise à jour):

Oups, désolé, le code de mon autre réponse ne fait pas tout à fait ce que vous voulez - il importe uniquement automatiquement les noms des sous-modules de package. Pour le faire également importer les attributs nommés de chaque sous-module nécessite quelques lignes de code supplémentaires. Voici une version modifiée du fichier __init__.py Du package (qui fonctionne également dans Python 3.4.1):

def _import_package_files():
    """ Dynamically import all the public attributes of the python modules in this
        file's directory (the package directory) and return a list of their names.
    """
    import os
    exports = []
    globals_, locals_ = globals(), locals()
    package_path = os.path.dirname(__file__)
    package_name = os.path.basename(package_path)

    for filename in os.listdir(package_path):
        modulename, ext = os.path.splitext(filename)
        if modulename[0] != '_' and ext in ('.py', '.pyw'):
            subpackage = '{}.{}'.format(package_name, modulename) # pkg relative
            module = __import__(subpackage, globals_, locals_, [modulename])
            modict = module.__dict__
            names = (modict['__all__'] if '__all__' in modict else
                     [name for name in modict if name[0] != '_'])  # all public
            exports.extend(names)
            globals_.update((name, modict[name]) for name in names)

    return exports

if __name__ != '__main__':
    __all__ = ['__all__'] + _import_package_files()  # '__all__' in __all__

Alternativement, vous pouvez placer ce qui précède dans un fichier de module .py distinct dans le répertoire du package, et l'utiliser à partir du __init__.py Du package comme ceci:

if __name__ != '__main__':
    from ._import_package_files import *  # defines __all__
    __all__.remove('__all__')  # prevent export (optional)

Quel que soit le nom que vous donnez au fichier, il doit s'agir d'un élément commençant par un caractère de soulignement _ Afin qu'il n'essaie pas de import lui-même de manière récursive.

12
martineau

Votre meilleure option, bien que probablement pas le meilleur style, est de tout importer dans l'espace de noms du package:

# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *

Ensuite, dans d'autres modules, vous pouvez importer ce que vous voulez directement à partir du package:

from subdir import Class1
6
Apalala

Je sais que cela fait quelques mois que cette question n'a pas reçu de réponse, mais je cherchais la même chose et j'ai parcouru cette page. Je n'étais pas très satisfait de la réponse choisie, alors j'ai fini par écrire ma propre solution et j'ai pensé la partager. Voici ce que j'ai trouvé:

# NOTE: The function name starts with an underscore so it doesn't get deleted by iself
def _load_modules(attr_filter=None):
    import os

    curdir = os.path.dirname(__file__)
    imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]

    pubattrs = {}
    for mod_name in imports:
        mod = __import__(mod_name, globals(), locals(), ['*'], -1)

        for attr in mod.__dict__:
            if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
                pubattrs[attr] = getattr(mod, attr)

    # Restore the global namespace to it's initial state
    for var in globals().copy():
        if not var.startswith('_'):
            del globals()[var]

    # Update the global namespace with the specific items we want
    globals().update(pubattrs)

# EXAMPLE: Only load classes that end with "Resource"
_load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
del _load_modules # Keep the namespace clean

Cela importe simplement * à partir de tous les fichiers .py du répertoire du package, puis extrait uniquement les fichiers publics dans l'espace de noms global. En outre, il autorise un filtre si seuls certains attributs publics sont souhaités.

5
Justin Warkentin

J'utilise cette façon simple:

  1. ajoutez le répertoire au chemin du système, puis
  2. import module ou from module import function1, class1 dans ce répertoire.

notez que le module n'est rien d'autre que le nom de votre *.py fichier, sans la partie extension.

Voici un exemple général:

import sys
sys.path.append("/path/to/folder/")
import module # in that folder

Dans votre cas, cela pourrait ressembler à ceci:

import sys
sys.path.append("subdir/")
import myclass01
# or
from myclass01 import func1, class1, class2 # .. etc
0
Aziz Alto