Réponses:
Il s'agit d'une liste d'objets publics de ce module, telle qu'interprétée par import *
. Il remplace la valeur par défaut de masquer tout ce qui commence par un trait de soulignement.
import *
(comme par exemple tk
). Un bon indice si tel est le cas est la présence de __all__
ou de noms commençant par un soulignement dans le code du module.
tk
étaient publiées aujourd'hui (ou même en 2012), la pratique recommandée serait d'utiliser from tk import *
. Je pense que la pratique est acceptée en raison de l'inertie et non de la conception intentionnelle.
Lié à, mais non explicitement mentionné ici, est exactement quand __all__
est utilisé. Il s'agit d'une liste de chaînes définissant quels symboles d'un module seront exportés lorsqu'il from <module> import *
est utilisé sur le module.
Par exemple, le code suivant dans un foo.py
exporte explicitement les symboles bar
et 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 ce qui __all__
précède est mis en commentaire, ce code s'exécutera ensuite jusqu'à la fin, car le comportement par défaut de import *
est d'importer tous les symboles qui ne commencent pas par un trait de soulignement, à partir de l'espace de noms donné.
Référence: https://docs.python.org/tutorial/modules.html#importing-from-a-package
REMARQUE: __all__
affecte from <module> import *
uniquement le comportement. Les membres non mentionnés dans __all__
sont toujours accessibles depuis l'extérieur du module et peuvent être importés avec from <module> import <member>
.
print(baz())
?
print(baz)
Imprime donc quelque chose comme <function baz at 0x7f32bc363c10>
alors print(baz())
imprimebaz
Expliquez __all__ en Python?
Je vois toujours la variable
__all__
définie dans différents__init__.py
fichiers.Qu'est-ce que cela fait?
__all__
-il?Il déclare les noms sémantiquement "publics" d'un module. S'il y a un nom __all__
, les utilisateurs devraient l'utiliser et ils peuvent s'attendre à ce qu'il ne change pas.
Il aura également des effets programmatiques:
import *
__all__
dans un module, par exemple module.py
:
__all__ = ['foo', 'Bar']
signifie que lorsque vous import *
depuis le module, seuls les noms dans le __all__
sont importés:
from module import * # imports foo and Bar
Les outils de documentation et d'auto-complétion de code peuvent (en fait, devraient) également inspecter le __all__
pour déterminer les noms à afficher comme disponibles à partir d'un module.
__init__.py
fait d'un répertoire un package PythonDe la documentation :
Les
__init__.py
fichiers sont nécessaires pour que Python traite les répertoires comme contenant des packages; cela est fait pour empêcher les répertoires avec un nom commun, tel que chaîne, de masquer involontairement des modules valides qui se produisent plus tard sur le chemin de recherche de module.Dans le cas le plus simple, il
__init__.py
peut simplement s'agir d'un fichier vide, mais il peut également exécuter le code d'initialisation du package ou définir la__all__
variable.
Ainsi, le __init__.py
peut déclarer le __all__
pour un package .
Un package est généralement composé de modules qui peuvent s’importer les uns les autres, mais qui sont nécessairement liés à un __init__.py
fichier. Ce fichier est ce qui fait du répertoire un véritable package Python. Par exemple, supposons que vous ayez les fichiers suivants dans un package:
package
├── __init__.py
├── module_1.py
└── module_2.py
Créons ces fichiers avec Python afin de pouvoir suivre - vous pouvez coller ce qui suit dans un shell Python 3:
from pathlib import Path
package = Path('package')
package.mkdir()
(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")
package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")
package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")
Et maintenant, vous avez présenté une API complète que quelqu'un d'autre peut utiliser lors de l'importation de votre package, comme ceci:
import package
package.foo()
package.Bar()
Et le package n'aura pas tous les autres détails d'implémentation que vous avez utilisés lors de la création de vos modules encombrant l' package
espace de noms.
__all__
dans __init__.py
Après plus de travail, vous avez peut-être décidé que les modules sont trop gros (comme plusieurs milliers de lignes?) Et doivent être divisés. Vous procédez donc comme suit:
package
├── __init__.py
├── module_1
│ ├── foo_implementation.py
│ └── __init__.py
└── module_2
├── Bar_implementation.py
└── __init__.py
Créez d'abord les sous-répertoires avec les mêmes noms que les modules:
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
Déplacez les implémentations:
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
créez des __init__.py
s pour les sous-packages qui déclarent le __all__
pour chacun:
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
Et maintenant, vous avez toujours l'api provisionné au niveau du package:
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
Et vous pouvez facilement ajouter des éléments à votre API que vous pouvez gérer au niveau du sous-package au lieu du niveau du module du sous-package. Si vous souhaitez ajouter un nouveau nom à l'API, il vous suffit de mettre à jour le __init__.py
, par exemple dans module_2:
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
Et si vous n'êtes pas prêt à publier Baz
dans l'API de niveau supérieur, dans votre niveau supérieur, __init__.py
vous pourriez avoir:
from .module_1 import * # also constrained by __all__'s
from .module_2 import * # in the __init__.py's
__all__ = ['foo', 'Bar'] # further constraining the names advertised
et si vos utilisateurs sont conscients de la disponibilité de Baz
, ils peuvent l'utiliser:
import package
package.Baz()
mais s'ils ne le savent pas, d'autres outils (comme pydoc ) ne les informeront pas.
Vous pouvez plus tard changer cela quand Baz
est prêt pour les heures de grande écoute:
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
_
contre __all__
:Par défaut, Python exportera tous les noms qui ne commencent pas par un _
. Vous avez certainement pu compter sur ce mécanisme. Certains paquets dans la bibliothèque standard de Python, en fait, ne comptent sur ce point , mais de le faire, ils alias leurs importations, par exemple, en ctypes/__init__.py
:
import os as _os, sys as _sys
L'utilisation de la _
convention peut être plus élégante car elle supprime la redondance de l'attribution de nouveaux noms. Mais cela ajoute la redondance des importations (si vous en avez beaucoup) et il est facile d'oublier de le faire de manière cohérente - et la dernière chose que vous voulez est de devoir prendre en charge indéfiniment quelque chose que vous vouliez être seulement un détail d'implémentation, juste parce que vous avez oublié de préfixer un _
lorsque vous nommez une fonction.
J'écris personnellement un __all__
début de mon cycle de vie de développement pour les modules afin que ceux qui pourraient utiliser mon code sachent ce qu'ils doivent utiliser et ne pas utiliser.
La plupart des packages de la bibliothèque standard utilisent également __all__
.
__all__
sensIl est logique de s'en tenir à la _
convention de préfixe au lieu de __all__
:
export
décorateurL'inconvénient de l'utilisation __all__
est que vous devez écrire deux fois les noms des fonctions et des classes exportées - et les informations sont séparées des définitions. Nous pourrions utiliser un décorateur pour résoudre ce problème.
J'ai eu l'idée d'un tel décorateur d'exportation à partir de l'exposé de David Beazley sur l'emballage. Cette implémentation semble bien fonctionner dans l'importateur traditionnel de CPython. Si vous avez un système ou un crochet d'importation spécial, je ne le garantis pas, mais si vous l'adoptez, il est assez banal de le retirer - vous aurez juste besoin d'ajouter manuellement les noms dans le__all__
Ainsi, par exemple, dans une bibliothèque d'utilitaires, vous définiriez le décorateur:
import sys
def export(fn):
mod = sys.modules[fn.__module__]
if hasattr(mod, '__all__'):
mod.__all__.append(fn.__name__)
else:
mod.__all__ = [fn.__name__]
return fn
puis, où vous définiriez un __all__
, vous faites ceci:
$ cat > main.py
from lib import export
__all__ = [] # optional - we create a list if __all__ is not there.
@export
def foo(): pass
@export
def bar():
'bar'
def main():
print('main')
if __name__ == '__main__':
main()
Et cela fonctionne bien, qu'il soit exécuté en tant que principal ou importé par une autre fonction.
$ cat > run.py
import main
main.main()
$ python run.py
main
Et le provisionnement d'API avec import *
fonctionnera également:
$ cat > run.py
from main import *
foo()
bar()
main() # expected to error here, not exported
$ python run.py
Traceback (most recent call last):
File "run.py", line 4, in <module>
main() # expected to error here, not exported
NameError: name 'main' is not defined
@export
décorateur.
__init__.py
et l'utilisation de__all__
__all__
c'est correct.
__all__
- mais alors je dirais que vous avez une API instable ... Ce serait quelque chose pour avoir des tests d'acceptation complets.
module_1
et module_2
; est-il OK d'inclure un explicite del module_1
dans __init__.py
? Ai-je tort de penser que cela en vaut la peine?
J'ajoute juste ceci pour être précis:
Toutes les autres réponses se réfèrent aux modules . La question d'origine est explicitement mentionnée __all__
dans les __init__.py
fichiers, il s'agit donc de packages python .
Généralement, __all__
n'entre en jeu que lorsque la from xxx import *
variante de l' import
instruction est utilisée. Cela s'applique aux packages ainsi qu'aux modules.
Le comportement des modules est expliqué dans les autres réponses. Le comportement exact des packages est décrit ici en détail.
En bref, __all__
au niveau du package fait à peu près la même chose que pour les modules, sauf qu'il traite des modules dans le package (contrairement à la spécification de noms dans le module ). Spécifie donc __all__
tous les modules qui doivent être chargés et importés dans l'espace de noms courant lorsque nous les utilisons from package import *
.
La grande différence est que lorsque vous omettez la déclaration de __all__
dans un package __init__.py
, l'instruction from package import *
n'importera rien du tout (avec des exceptions expliquées dans la documentation, voir le lien ci-dessus).
D'un autre côté, si vous omettez __all__
dans un module, l '"importation étoilée" 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 en a pas all
. La différence importante est que sans __all__
cela, il n'importera pas automatiquement les modules définis dans le répertoire du package.
Cela change également ce que pydoc affichera:
module1.py
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc module1
Aide sur le module module1: NOM module 1 FICHIER module1.py DONNÉES a = 'A' b = 'B' c = 'C'
$ pydoc module2
Aide sur le module module2: NOM module2 FICHIER module2.py DONNÉES __all__ = ['a', 'b'] a = 'A' b = 'B'
Je déclare __all__
dans tous mes modules, ainsi que les détails internes soulignés, que cela aide vraiment lorsque vous utilisez des choses que vous n'avez jamais utilisées auparavant dans des sessions d'interprétariat en direct.
__all__
personnalise *
enfrom <module> import *
__all__
personnalise *
enfrom <package> import *
Un module est un .py
fichier destiné à être importé.
Un package est un répertoire avec un __init__.py
fichier. Un package contient généralement des modules.
""" cheese.py - an example module """
__all__ = ['swiss', 'cheddar']
swiss = 4.99
cheddar = 3.99
gouda = 10.99
__all__
permet aux humains de connaître les fonctionnalités "publiques" d'un module . [ @AaronHall ] De plus, pydoc les reconnaît. [ @Longpoke ]
Voyez comment swiss
et cheddar
sont introduits dans l'espace de noms local, mais pas gouda
:
>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined
Sans __all__
, aucun symbole (qui ne commence pas par un trait de soulignement) aurait été disponible.
*
sont pas affectées par__all__
>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)
>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)
>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)
Dans le __init__.py
fichier d'un package se __all__
trouve une liste de chaînes avec les noms des modules publics ou d'autres objets. Ces fonctionnalités sont disponibles pour les importations de caractères génériques. Comme avec les modules, __all__
personnalise *
lors de l'importation de caractères génériques à partir du package. [ @MartinStettner ]
Voici un extrait du connecteur Python MySQL __init__.py
:
__all__ = [
'MySQLConnection', 'Connect', 'custom_error_exception',
# Some useful constants
'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
'HAVE_CEXT',
# Error handling
'Error', 'Warning',
...etc...
]
Le cas par défaut, astérisque sans no __all__
pour un package , est compliqué, car le comportement évident serait coûteux: utiliser le système de fichiers pour rechercher tous les modules du package. Au lieu de cela, dans ma lecture des documents, seuls les objets définis dans __init__.py
sont importés:
Si
__all__
non défini, l'instructionfrom sound.effects import *
ne pas importer toutes les sous - modules du packagesound.effects
dans l'espace de noms en cours; il garantit uniquement que le packagesound.effects
a été importé (éventuellement en exécutant n'importe quel code d'initialisation__init__.py
), puis importe les noms définis dans le package. Cela inclut tous les noms définis (et les sous-modules explicitement chargés) par__init__.py
. Il inclut également tous les sous-modules du package qui ont été explicitement chargés par les instructions d'importation précédentes.
Les importations de caractères génériques ... doivent être évitées car elles [confondent] les lecteurs et de nombreux outils automatisés.
[ PEP 8 , @ToolmakerSteve]
from <package> import *
sans __all__
en __init__.py
qui n'importer l' un des modules .
__init__.py
s'agissait d'un module . Mais je ne suis pas sûr que ce soit exact, ou en particulier si les objets avec préfixe de soulignement sont exclus. De plus, j'ai séparé plus clairement les sections sur les MODULES et les FORFAITS. Tes pensées?
Du (Un Unofficial) Wiki de Référence 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 s'agir d'une séquence de chaînes dont les noms sont définis ou importés par ce module. Les noms indiqués__all__
sont tous considérés comme publics et doivent exister. Si__all__
n'est pas défini, l'ensemble des noms publics inclut 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. Il est destiné à éviter d'exporter accidentellement des éléments qui ne font pas partie de l'API (tels que les modules de bibliothèque qui ont été importés et utilisés dans le module).
__all__
est utilisé pour documenter l'API publique d'un module Python. Bien qu'il soit facultatif, __all__
doit être utilisé.
Voici l'extrait pertinent de la référence du langage 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 s'agir d'une séquence de chaînes dont les noms sont définis ou importés par ce module. Les noms indiqués__all__
sont tous considérés comme publics et doivent exister. Si__all__
n'est pas défini, l'ensemble des noms publics inclut 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. Il est destiné à éviter d'exporter accidentellement des éléments qui ne font pas partie de l'API (tels que les modules de bibliothèque qui ont été importés et utilisés dans le module).
PEP 8 utilise une formulation similaire, bien qu'il indique également clairement que les noms importés ne font pas partie de l'API publique en cas d' __all__
absence:
Pour mieux prendre en charge l'introspection, les modules doivent déclarer explicitement les noms dans leur API publique à l'aide de l'
__all__
attribut. La définition__all__
d'une liste vide indique que le module n'a pas d'API publique.[...]
Les noms importés doivent toujours être considérés comme un détail d'implémentation. Les autres modules ne doivent pas s'appuyer sur un accès indirect à ces noms importés, sauf s'ils font partie explicitement documentée de l'API du module conteneur, tel que
os.path
le__init__
module d' un package qui expose les fonctionnalités des sous-modules.
En outre, comme indiqué dans d'autres réponses, __all__
est utilisé pour activer l' importation de caractères génériques pour les packages :
L'instruction import utilise la convention suivante: si le
__init__.py
code d' un package définit une liste nommée__all__
, elle est considérée comme la liste des noms de module qui doivent être importés lorsqu'ilfrom package import *
est rencontré.
__all__
affecte les from <module> import *
déclarations.
Considérez cet exemple:
foo
├── bar.py
└── __init__.py
Dans foo/__init__.py
:
(Implicite) Si nous ne définissons pas __all__
, alors from foo import *
importera uniquement les noms définis dans foo/__init__.py
.
(Explicite) Si nous définissons __all__ = []
, alors from foo import *
n'importera rien.
(Explicite) Si nous définissons __all__ = [ <name1>, ... ]
, alors from foo import *
importera uniquement ces noms.
Notez que dans le cas implicite, python n'importera pas de noms commençant par _
. Cependant, vous pouvez forcer l'importation de ces noms à l'aide de __all__
.
Vous pouvez voir le document Python ici .
__all__
affecte la façon dont from foo import *
fonctionne.
Le code qui se trouve à l'intérieur d'un corps de module (mais pas dans le corps d'une fonction ou d'une classe) peut utiliser un astérisque ( *
) dans une from
instruction:
from foo import *
Les *
demandes que tous les attributs du module foo
(à l'exception de ceux commençant par des traits de soulignement) soient liés en tant que variables globales dans le module d'importation. Lorsqu'il foo
a un attribut __all__
, la valeur de l'attribut est la liste des noms liés par ce type de from
déclaration.
Si foo
est un package et qu'il __init__.py
définit une liste nommée __all__
, il est considéré comme la liste des noms de sous-modules qui doivent être importés lorsqu'il from foo import *
est rencontré. Si __all__
n'est pas défini, l'instruction from foo import *
importe les noms définis dans le package. Cela inclut tous les noms définis (et les sous-modules explicitement chargés) par __init__.py
.
Notez que __all__
cela ne doit pas nécessairement être une liste. Selon la documentation de l' import
instruction , si elle est définie, elle __all__
doit être une séquence de chaînes qui sont des noms définis ou importés par le module. Vous pouvez donc aussi bien utiliser un tuple pour économiser de la mémoire et des cycles CPU. N'oubliez pas une virgule au cas où le module définirait un seul nom public:
__all__ = ('some_name',)
Voir aussi Pourquoi «importer *» est-il mauvais?
Ceci est défini dans PEP8 ici :
Noms de variables globales
(Espérons que ces variables sont destinées à être utilisées dans un seul module.) Les conventions sont à peu près les mêmes que celles des fonctions.
Les modules conçus pour être utilisés via
from M import *
doivent utiliser le__all__
mécanisme pour empêcher l'exportation de globaux, ou utiliser l'ancienne convention consistant à préfixer ces globaux avec un trait de soulignement (ce que vous voudrez peut-être faire pour indiquer que ces globaux sont "module non public").
PEP8 fournit des conventions de codage pour le code Python comprenant la bibliothèque standard dans la distribution Python principale. Plus vous suivez cela, plus vous êtes proche de l'intention d'origine.
__all__
si__all__
est présent, ne sont pas exactement cachés; ils peuvent être vus et consultés parfaitement normalement si vous connaissez leurs noms. Ce n'est que dans le cas d'une "importation", ce qui n'est pas recommandé de toute façon, que la distinction a un poids.