Il me manque probablement quelque chose d'évident mais de toute façon:
Lorsque vous importez un paquet tel que os
en python, vous pouvez utiliser n’importe quel sous-module/sous-paquetage. Par exemple cela fonctionne:
>>> import os
>>> os.path.abspath(...)
Cependant, j'ai mon propre paquet qui est structuré comme suit:
FooPackage/
__init__.py
foo.py
et ici la même logique ne fonctionne pas:
>>> import FooPackage
>>> FooPackage.foo
AttributeError: 'module' object has no attribute 'foo'
Qu'est-ce que je fais mal?
Vous devez importer le sous-module:
import FooPackage.foo
Ce que vous faites est à la recherche de foo
dans FooPackage/__init__.py
. Vous pouvez le résoudre en mettant import FooPackage.foo as foo
(ou from . import foo
) dans FooPackage/__init__.py
, alors Python pourra y trouver foo
. Mais je vous recommande d’utiliser ma première suggestion.
Lorsque vous importez FooPackage
, Python) recherche dans les répertoires de PYTHONPATH jusqu'à ce qu'il trouve un fichier appelé FooPackage.py
ou un répertoire appelé FooPackage
contenant un fichier nommé __init__.py
. Cependant, après avoir trouvé le répertoire du paquet, il pas puis analyse ce répertoire et importe automatiquement tous les fichiers .py.
Il y a deux raisons à ce comportement. La première est que l'importation d'un module exécute le code Python qui peut prendre du temps, de la mémoire ou des effets secondaires. Vous pouvez donc importer a.b.c.d
_ sans nécessairement importer la totalité d'un énorme paquet a
. C'est au créateur de paquets de décider si un __init__.py
importe explicitement ses modules et sous-packages afin qu'ils soient toujours disponibles, ou laisse ou non au programme client la possibilité de choisir ce qui est chargé.
La seconde est un peu plus subtile et constitue également un obstacle. Sans une déclaration d'importation explicite (soit dans FooPackage/__init__.py
ou dans le programme client), Python ne sait pas nécessairement quel nom il doit importer foo.py
comme. Sur un système de fichiers ne faisant pas la distinction entre les majuscules et les minuscules (comme dans Windows), cela pourrait représenter un module nommé foo
, Foo
, FOO
, fOo
, foO
, FoO
, FOo
ou fOO
. Tous ces éléments sont des identifiants valides et distincts Python, donc Python ne contient pas assez d'informations du fichier seul pour savoir ce que vous voulez dire. Par conséquent, dans Afin de se comporter de manière cohérente sur tous les systèmes, cela nécessite une instruction d'importation explicite quelque part pour clarifier le nom, même sur les systèmes de fichiers où des informations de cas complètes sont disponibles.
Vous devez ajouter from . import foo
au __init__.py
fichier dans votre paquet.
Certaines idées fausses importantes doivent être abordées, notamment en ce qui concerne la terminologie. Tout d’abord, généralement, lorsque vous pensez importer un package
en python, vous importez en réalité un module
. Vous devriez utiliser le terme package
lorsque vous pensez en termes de sous-structure de système de fichiers qui vous aide à organiser votre code. Mais du point de vue du code, chaque fois que vous importez un package
, Python le traite comme un module. Tous les packages sont des modules. Tous les modules ne sont pas des packages. Un module avec le __path__
attribut est considéré comme un paquet.
Vous pouvez vérifier que os
est un module. Pour le confirmer, vous pouvez faire:
import os
print(type(os)) # will print: <type 'module'>
Dans votre exemple, quand vous faites import FooPackage
, FooPackage
est traité et considéré comme un module également, et ses attributs (fonctions, classes, etc.) sont supposés être définis dans __init__.py
. Depuis votre __init__.py
est vide, il ne peut pas trouver foo
.
En dehors des instructions import
, vous ne pouvez pas utiliser '.'
notation pour adresser les modules à l'intérieur des modules. La seule exception se produit si un module
est importé dans le paquet du parent prévu __init__.py
fichier. Pour bien comprendre, faisons quelques exemples ici:
Considérez votre structure d'origine:
FooPackage/
__init__.py
foo.py
Cas 1: __init__.py est un fichier vide
#FooPackage imported as a module
import FooPackage
#foo is not a name defined in `__init__.py`. Error
FooPackage.foo
#FooPackage.foo imported as a module
import FooPackage.foo
#Error, foo has not been imported. To be able to use foo like this,
#you need to do: import FooPackage.foo as foo
foo.anything
#Not error, if anything is defined inside foo.py
FooPackage.foo.anything
Cas 2: __init__.py a la ligne import foo
dedans:
import FooPackage
#Now this is good. `foo` is sort of considered to be an attribute of
#FooPackage
FooPackage.foo
Supposons maintenant que foo ne soit plus un module
, mais un function
que vous définissez dans __init__.py
. si tu fais import FooPackage.foo
, il générera une erreur disant que foo
n’est pas un module.