J'utilise de plus en plus Python, et je continue à voir la variable __all__
dans différents __init__.py
fichiers. Quelqu'un peut-il expliquer ce que cela fait ?
Ne devrions-nous pas imprimer baz comme print(baz())
?
J'utilise de plus en plus Python, et je continue à voir la variable __all__
dans différents __init__.py
fichiers. Quelqu'un peut-il expliquer ce que cela fait ?
Lié à cela, mais pas explicitement mentionné ici, est le moment exact où __all__
est utilisé. Il s'agit d'une liste de chaînes de caractères définissant quels symboles d'un module seront exportés lorsque from <module> import *
est utilisé sur le module.
Par exemple, le code suivant dans un foo.py
exporte explicitement les symboles bar
y baz
:
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'
Ces symboles peuvent ensuite être importés comme suit :
from foo import *
print(bar)
print(baz)
# The following will trigger an exception, as "waz" is not exported by the module
print(waz)
Si le __all__
ci-dessus est commenté, ce code s'exécutera alors jusqu'au bout, car le comportement par défaut de l'option import *
est d'importer tous les symboles qui ne commencent pas par un trait de soulignement, à partir de l'espace de nom donné.
Référence : https://docs.python.org/tutorial/modules.html#importing-from-a-package
NOTE : __all__
affecte le from <module> import *
comportement uniquement. Les membres qui ne sont pas mentionnés dans __all__
sont toujours accessibles depuis l'extérieur du module et peuvent être importés avec la commande from <module> import <member>
.
@BhanuTez exactement. Donc print(baz)
imprime quelque chose comme <function baz at 0x7f32bc363c10>
alors que print(baz())
imprime baz
Les objets qui commencent par un trait de soulignement, ou qui ne sont pas mentionnés dans la liste des objets de l'UE. __all__
si __all__
est présent, ne sont pas exactement cachés ; on peut les voir et y accéder parfaitement normalement si l'on connaît leur nom. Ce n'est que dans le cas d'un "import *", qui n'est de toute façon pas recommandé, que la distinction a un quelconque poids.
@BrandonRhodes : ce n'est pas tout à fait vrai non plus : Il est recommandé de n'importer que les modules dont vous savez qu'ils ont été conçus pour import *
(comme par exemple tk
). Un bon indice si c'est le cas est la présence de __all__
ou les noms commençant par un trait de soulignement dans le code du module.
Interfaces publiques et internes - python.org/dev/peps/pep-0008/#id50 Pour mieux prendre en charge l'introspection, les modules doivent déclarer explicitement les noms dans leur API publique à l'aide de l'attribut __all__. Le fait de définir __all__ sur une liste vide indique que le module n'a pas d'API publique.
J'ajoute juste ça pour être précis :
Toutes les autres réponses font référence à modules . La question originale mentionnait explicitement __all__
en __init__.py
donc il s'agit de python paquets .
En général, __all__
n'entre en jeu que lorsque le from xxx import *
variante de la import
est utilisée. Cela s'applique aussi bien aux paquets qu'aux modules.
Le comportement des modules est expliqué dans les autres réponses. Le comportement exact pour les paquets est décrit aquí en détail.
En bref, __all__
au niveau des paquets fait à peu près la même chose que pour les modules, sauf qu'il s'occupe de modules du paquet (contrairement à la spécification de les noms dans le module ). Ainsi, __all__
spécifie tous les modules qui doivent être chargés et importés dans l'espace de noms actuel lorsque nous utilisons le module from package import *
.
La grande différence est que, lorsque vous omettre la déclaration de __all__
dans un paquet __init__.py
la déclaration from package import *
n'importera rien du tout (sauf exceptions expliquées dans la documentation, voir le lien ci-dessus).
D'autre part, si vous omettez __all__
dans un module, le "starred import" importera tous les noms (ne commençant pas par un trait de soulignement) définis dans le module.
from package import *
importera toujours tout ce qui est défini dans __init__.py
même s'il n'y a pas de all
. La différence importante est que sans __all__
il n'importera pas automatiquement les modules définis dans le répertoire du paquet.
Cela change aussi ce que pydoc va montrer :
module1.py
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc module1
Help on module module1:
**NAME**
module1
**FILE**
module1.py
**DATA**
**a** = 'A'
**b** = 'B'
**c** = 'C'
$ pydoc module2
Help on module module2:
**NAME**
module2
**FILE**
module2.py
**DATA**
**\_\_all\_\_** = \['a', 'b'\]
**a** = 'A'
**b** = 'B'
Je déclare __all__
dans tous mes modules, ainsi que de souligner les détails internes, ce qui est très utile lorsque vous utilisez des choses que vous n'avez jamais utilisées auparavant dans des sessions d'interprétation en direct.
Desde Wiki de référence (non officiel) sur Python :
Les noms publics définis par un module sont déterminés en vérifiant l'espace de noms du module pour une variable nommée
__all__
; s'il est défini, il doit être une séquence de chaînes de caractères qui sont des noms définis ou importés par ce module. Les noms donnés dans__all__
sont toutes considérées comme publiques et sont tenues d'exister. Si__all__
n'est pas défini, l'ensemble des noms publics comprend tous les noms trouvés dans l'espace de noms du module qui ne commencent pas par un caractère de soulignement ("_").__all__
doit contenir l'intégralité de l'API publique. L'objectif est d'éviter d'exporter accidentellement des éléments qui ne font pas partie de l'API (comme les modules de bibliothèque qui ont été importés et utilisés dans le module).
Le lien indiqué est mort, mais j'ai trouvé le texte textuel sur le site suivant vdocuments.net/ & ici : dokumen.tips/documents/reference-567bab8d6118a.html
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.