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'
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.
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
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.
J'utilise cette façon simple:
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