Question

J'ai été en utilisant Python de plus en plus, et je continue à voir la variable __all__ situés dans différents __init__.py les fichiers.Quelqu'un peut m'expliquer ce que cela fait?

Était-ce utile?

La solution

C'est une liste des objets de ce module, tel qu'interprété par import *.Il remplace la valeur par défaut de cacher tout ce qui commence par un trait de soulignement.

Autres conseils

Liés à, mais pas explicitement mentionné ici, est exactement quand __all__ est utilisée.C'est une liste de chaînes de définition de ce que les symboles dans un module sera exporté lors de la from <module> import * est utilisé sur le module.

Par exemple, le code suivant dans un foo.py explicitement les exportations les symboles bar et baz:

__all__ = ['bar', 'baz']

waz = 5
bar = 10
def baz(): return 'baz'

Ces symboles peuvent être ensuite importés de la sorte:

from foo import *

print(bar)
print(baz)

# The following will trigger an exception, as "waz" is not exported by the module
print(waz)

Si l' __all__ ci-dessus est commenté, ce code s'exécutera alors à la fin, comme le comportement par défaut de import * est pour 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

NOTE: __all__ affecte le from <module> import * comportement.Les membres qui ne sont pas mentionnés dans __all__ sont toujours accessible depuis l'extérieur du module et peut être importé avec from <module> import <member>.

Je suis juste en ajoutant ceci à être précis:

Toutes les autres réponses se réfèrent à les modules de.La question d'origine explicitement mentionné __all__ dans __init__.py fichiers, de sorte que c'est à propos de python les paquets.

Généralement, __all__ n'intervient que lorsque l' from xxx import * variante de la import l'instruction est utilisée.Cela s'applique aux paquets ainsi que pour les modules.

Le comportement pour les modules est expliqué dans les autres réponses.Le comportement exact pour les paquets qui est décrit ici dans le détail.

En bref, __all__ sur l'emballage, ce n'est environ la même chose que pour les modules, sauf qu'il traite les modules de l'intérieur de l'emballage (contrairement à la spécification les noms dans le module).Donc __all__ spécifie tous les modules qui doivent être chargés et importés dans l'espace de noms courant lors de l'utilisation from package import *.

La grosse différence est que lorsque vous omettre la déclaration de __all__ dans un paquet __init__.py, la déclaration from package import * ne pas importer de rien du tout (avec des exceptions expliqué dans la documentation, voir le lien ci-dessus).

D'autre part, si vous omettez __all__ dans un module, le "étoilé importer" importer tous les noms (ne commençant pas par un trait de soulignement) est définie dans le module.

Expliquez __tous__ en Python?

Je continue à voir la variable __all__ situés dans différents __init__.py les fichiers.

À quoi ça sert?

Ce n' __all__ faire?

Il déclare la sémantiquement "public" des noms à partir d'un module.Si il y a un nom dans __all__, les utilisateurs sont invités à l'utiliser, et ils peuvent avoir l'espoir qu'il ne changera pas.

Il aura aussi programmatique affecte:

import *

__all__ dans un module, par exemple module.py:

__all__ = ['foo', 'Bar']

signifie que lorsque vous import * à partir de ce module, seuls les noms dans le __all__ sont importés:

from module import *               # imports foo and Bar

Outils de Documentation

La Documentation et le code d'auto-complétion outils (en fait, doit) aussi inspecter les __all__ afin de déterminer quels noms pour montrer comme disponibles à partir d'un module.

__init__.py fait un répertoire d'un paquet Python

À partir de la docs:

L' __init__.py les fichiers sont requis pour assurer le Python traiter les répertoires contenant des paquets;ceci est fait pour empêcher les répertoires avec un nom commun, tels que la chaîne, à partir involontairement cacher valide les modules qui se produisent plus tard dans le module de recherche de chemin.

Dans le cas le plus simple, __init__.py peut-être simplement un fichier vide, mais il peut également exécuter du code d'initialisation pour le paquet ou ensemble de la __all__ variable.

De sorte que le __init__.py pouvez déclarer la __all__ pour un package.

La gestion d'une API:

Un forfait est généralement constitué de modules qui peuvent importer l'un de l'autre, mais qui sont nécessairement attachés ensemble avec une __init__.py fichier.Ce fichier est ce qui rend le répertoire d'un réel paquet Python.Par exemple, disons que vous avez les éléments suivants:

 package/
   |-__init__.py # makes directory a Python package
   |-module_1.py
   |-module_2.py

dans le __init__.py vous écrivez:

from module_1 import *
from module_2 import *

et dans module_1 vous avez:

__all__ = ['foo',]

et dans module_2 vous avez:

__all__ = ['Bar',]

Et maintenant, vous avez présenté une api complète que quelqu'un d'autre peut utiliser de l'importation de votre colis, comme suit:

import package
package.foo()
package.Bar()

Et ils n'ont pas tous les autres noms que vous avez utilisé lors de la création de vos modules d'encombrer l' package espace de noms.

__all__ dans __init__.py

Après plus de travail, peut-être que vous avez décidé que les modules sont trop gros et doivent être séparés.Si vous procédez de la manière suivante:

 package/
   |-__init__.py
   |-module_1/
   |  |-__init__.py
   |  |-foo_implementation.py
   |-module_2/
      |-__init__.py
      |-Bar_implementation.py

Et dans chaque __init__.py vous déclarez un __all__, par exempledans module_1:

from foo_implementation import *
__all__ = ['foo']

Et module_2 de l' __init__.py:

from Bar_implementation import *
__all__ = ['Bar']

Et vous pouvez facilement ajouter des choses à votre API que vous pouvez gérer au sous-paquetage niveau de la place de la sous-paquetage du module.Si vous voulez ajouter un nouveau nom à l'API, il vous suffit de mettre à jour le __init__.py, par exempledans module_2:

from Bar_implementation import *
from Baz_implementation import *
__all__ = ['Bar', 'Baz']

Et si vous n'êtes pas prêt à publier Baz dans le premier niveau de l'API, dans votre top niveau __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 informés de l'existence de Baz, ils peuvent l'utiliser:

import package
package.Baz()

mais si ils ne savent pas à ce sujet, d'autres outils (comme pydoc) de ne pas informer.

Vous pourrez par la suite changer que lorsque Baz est prêt pour le prime time:

from module_1 import *
from module_2 import *
__all__ = ['foo', 'Bar', 'Baz']

La préfixation _ rapport __all__:

Par défaut, Python exporter tous les noms qui ne démarre pas avec un _.Vous avez certainement pourrait s'appuyer sur ce mécanisme.Certains paquets dans le Python standard library, en fait, faire compter sur cela, mais pour ce faire, ils alias leurs importations, par exemple, dans ctypes/__init__.py:

import os as _os, sys as _sys

À l'aide de la _ la convention peut être plus élégante, car elle élimine la redondance de nommer des noms.Mais il ajoute de la redondance pour les importations (si vous avez beaucoup d'entre eux) et c'est facile oublier de faire systématiquement - et la dernière chose que vous voulez est d'avoir indéfiniment l'appui de quelque chose que vous destinée à n'être qu'un détail d'implémentation, juste parce que vous avez oublié de le préfixe d'un _ lors de la dénomination d'une fonction.

Personnellement, j'écris un __all__ dès le début de mon cycle de développement de modules, de sorte que d'autres personnes qui pourraient utiliser mon code savent ce qu'ils doivent utiliser et ne pas utiliser.

La plupart des paquets dans la bibliothèque standard également utiliser __all__.

Lors de l'éviter __all__ sens

Il fait sens pour coller à l' _ préfixe convention en lieu et place de __all__ quand:

  • Vous êtes encore au début de leur mode de développement et n'ont pas les utilisateurs, et sont constamment peaufiner votre API.
  • Peut-être que vous avez des utilisateurs, mais vous avez unittests qui couvrent l'API, et vous êtes toujours activement l'ajout de l'API et de peaufinage dans le développement.

Un export décorateur

L'inconvénient de l'utilisation de __all__ est-ce que vous avez à écrire les noms de fonctions et de classes exporté deux fois - et les informations sont tenues à l'écart des définitions.Nous pourrait l'utilisation d'un décorateur pour résoudre ce problème.

J'ai eu l'idée d'une telle exportation décorateur de David Beazley parler sur l'emballage.Cette mise en œuvre semble bien fonctionner dans Disponible traditionnelles de l'importateur.Si vous avez un spécial à l'importation de crochet ou d'un système, je n'ai pas de garantie, mais si vous l'adopter, il est assez trivial de retour - vous avez juste besoin d'ajouter manuellement les noms de retour dans le __all__

Ainsi, par exemple, une bibliothèque utilitaire, vous définissez 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

et puis, si vous définissez un __all__, pour ce faire:

$ 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 très bien s'exécuter en tant que principal ou importés par une autre fonction.

$ cat > run.py
import main
main.main()

$ python run.py
main

Des API et de l'approvisionnement en import * sera trop de travail:

$ 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

Il change aussi de 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

Help on module module1:

NOM
    module1

FICHIER
    module1.py

DONNÉES
    un = 'A'
    b = 'B'
    c = 'C'

$ pydoc module2

Help on module module2:

NOM
    module2

FICHIER
    module2.py

DONNÉES
    __tous__ = ['a', 'b']
    un = 'A'
    b = 'B'

Je déclare __all__ dans tous mes modules, ainsi que de souligner des détails internes, ces vraiment aider lors de l'utilisation de choses que vous n'avez jamais utilisé avant d'interprète en live sessions.

À partir de (Non Officiel) De Référence Sur Python Wiki:

Le public de noms définis par un module sont déterminés par la vérification du module de l'espace de noms pour une variable nommée __all__;si elle est définie, elle 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 considérés comme publics et nécessaire à l'existence.Si __all__ n'est pas défini, l'ensemble des noms publics comprend tous les noms contenus dans le module de l'espace de noms qui ne commence pas par un caractère de soulignement ("_"). __all__ doit contenir l'ensemble de l'API publique.Il est destiné à éviter accidentellement de l'exportation des éléments qui ne font pas partie de l'API (comme la bibliothèque de modules qui ont été importés et utilisés dans le module).

__all__ personnalise l'astérisque dans from <module> import *

__all__ personnalise l'astérisque dans from <package> import *


Un module est un .py fichier destiné à être importé.

Un package est un répertoire avec un __init__.py fichier.Un paquet contient généralement des modules.


Les MODULES de

""" cheese.py - an example module """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__ permet à l'homme de savoir le "public" caractéristiques d'un module.[@AaronHall] Aussi, pydoc les reconnaît.[@Longpoke]

à partir de module importation *

Voir 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__, un symbole (qui ne commence pas par un caractère de soulignement) aurait été disponible.


Les importations sans * ne sont pas concernés par __all__


l'importation module

>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)

à partir de module l'importation les noms de

>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)

l'importation module comme localname

>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)

Les PAQUETS

Dans le __init__.py fichier de un package __all__ est une liste de chaînes de caractères avec le nom de public modules ou d'autres objets.Ces fonctionnalités sont disponibles pour les génériques des importations.Comme avec les modules, __all__ personnalise la * quand générique-l'importation de l'emballage.[@MartinStettner]

Voici un extrait de la Python MySQL Connector __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, asterisk avec pas de __all__ pour un paquet, est compliqué, parce que l'évidence le comportement serait coûteux:pour utiliser le système de fichiers à la recherche de tous les modules dans le package.Au lieu de cela, dans ma lecture de la documentation, seuls les objets définis dans __init__.py sont importés:

Si __all__ n'est pas défini, l'instruction from sound.effects import * n' pas importer tous les submodules de l'emballage sound.effects en l'espace de noms courant;il permet uniquement de s'assurer que le package sound.effects a été importé (éventuellement, d'exécuter tout code d'initialisation dans __init__.py) et puis importe les noms sont définis dans le package.Cela comprend tous les noms définis (et submodules chargée explicitement) par __init__.py.Il comprend également les submodules de l'emballage qui ont été expressément chargé par de précédentes déclarations d'importation.


Générique importations ...doivent être évités car ils [confondre] les lecteurs et de nombreux outils automatisés.

[PEP 8, @ToolmakerSteve]

Réponse courte

__all__ affecte from <module> import * des déclarations.

Réponse longue

Considérons cet exemple:

foo
├── bar.py
└── __init__.py

Dans foo/__init__.py:

  • (Implicite) Si nous ne définissons pas __all__, puis from foo import * continuera d'importer les noms définis dans foo/__init__.py.

  • (Explicite) Si l'on définit __all__ = [], puis from foo import * d'importation rien.

  • (Explicite) Si l'on définit __all__ = [ <name1>, ... ], puis from foo import * ne l'importation de ces noms.

Notez que dans l'implicite cas, python ne pas importer des noms commençant par _.Cependant, vous pouvez forcer l'importation de tels noms à l'aide de __all__.

Vous pouvez consulter le document Python ici.

__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 au langage Python:

Le public de noms définis par un module sont déterminés par la vérification du module de l'espace de noms pour une variable nommée __all__;si elle est définie, elle 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 considérés comme publics et nécessaire à l'existence.Si __all__ n'est pas défini, l'ensemble des noms publics comprend tous les noms contenus dans le module de l'espace de noms qui ne commence pas par un caractère de soulignement ('_'). __all__ doit contenir l'ensemble de l'API publique.Il est destiné à éviter accidentellement de l'exportation des éléments qui ne font pas partie de l'API (comme la bibliothèque de modules qui ont été importés et utilisés dans le module).

PEP 8 utilise un libellé similaire, bien qu'il indique clairement que l'importation des noms ne font pas partie de l'API publique lors de l' __all__ est absent:

Afin de mieux soutenir l'introspection, les modules doivent déclarer explicitement les noms dans leur API publique à l'aide de la __all__ attribut.Réglage __all__ pour une liste vide indique que le module n'a pas d'API publique.

[...]

Importés noms devraient toujours être considéré comme un détail d'implémentation.D'autres modules ne doivent pas compter sur un accès indirect à ces noms importés, sauf s'ils sont explicitement documentées partie de l'contenant du module API, tels que os.path ou d'un package __init__ module qui expose la fonctionnalité de submodules.

En outre, comme l'a souligné dans d'autres réponses, __all__ est utilisé pour activer générique de l'importation de paquets:

L'instruction import utilise la convention suivante:si un paquet __init__.py code définit une liste nommée __all__, il est pris à la liste des noms de modules qui doivent être importés lors de la from package import * est rencontrée.

En plus des réponses, __all__ ne doit pas être une liste.Selon la documentation sur l' import déclaration, si défini, __all__ doit être un séquence de chaînes de caractères qui sont des noms définis ou importés par le module.De sorte que vous pourriez aussi bien utiliser un tuple à enregistrer un peu de mémoire et de cycles de PROCESSEUR.Il suffit de ne pas oublier une virgule dans le cas où le module définit un seul nom public:

__all__ = ('some_name',)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top