À propos du système d'importation Python
.py
--Package est le répertoire où se trouve __init __. Py
Vous pouvez comprendre que, En s'éloignant des fichiers physiques et en réfléchissant un peu plus abstraitement, je pense que la visibilité de l'ensemble du système, comme les noms de modules, les importations relatives, le moment d'initialisation et la visibilité des noms, sera améliorée.
Notez que cet article ne couvre pas les ** packages d'espace de noms [^ 1] ** (car je ne les comprends pas).
J'ai parcouru la version v3.8.2 des deux.
Confirmé pour fonctionner avec Python v3.8.2. Vérifiez l'opération en tant que cas de test de pytest.
pip install pytest
Voir l'annexe pour vérifier le fonctionnement du pytest lui-même.
Un bref résumé des attributs:
__name__ |
__path__ |
__package__ |
|
---|---|---|---|
module: | module名 | Aucun | Nom du package parent |
paquet: | paquet名 | paquetのパス | paquet名 |
C'est un concept couramment utilisé dans les langages de programmation
** Il s'agit d'une fonction qui vous permet d'utiliser des "noms" tels que le nom de variable "x" à différents endroits du programme avec des significations différentes sans crainte de collision. ** **
Par exemple, builtins.open
et ʻos.open` sont tous deux des noms de fonction, mais parce qu'ils appartiennent à des espaces de noms différents.
Peut être défini et utilisé comme différent.
Le "module" décrit ci-dessous est cette ** unité d'espace de noms **.
Il existe un glossaire dans la documentation Python avec une entrée "namespace": https://docs.python.org/ja/3/glossary.html#term-namespace
Comme mentionné dans la présentation, un module est une ** unité d'espace de noms qui peut être importée **.
Premièrement, parce qu'un module est une unité d'espace de noms, pour les modules m
et n
, le nom dans m`` x
(= mx
) et le nom dans n`` x
(= nx
) Se distingue.
Deuxièmement, moins consciemment, tout le code s'exécute dans un module, c'est-à-dire dans un espace de noms.
Lorsque le code déclare et définit un nom, il est enregistré dans cet espace de noms.
Immédiatement après le lancement de l'interpréteur Python, le code s'exécute dans l'espace de noms du module ** __ main__
**.
Ceci est souvent utilisé pour ** une manière de savoir si un fichier .py
a été lancé directement ou importé **.
Le module peut ensuite être importé. Importer un module signifie
--Trouver et mettre en cache le module et
C'est. Le document dit 2 étapes, mais si vous le considérez comme 3 étapes, l'unité de traitement est facile à comprendre.
En termes simples, en important le module m
comme ʻimport m`
m
dans sys.path
et enregistrez l'objet module dans le cache global sys.modules
.m
. Par exemple, «m.f» ou «m.C».m
dans l'espace de noms courant afin qu'il pointe vers le module m
.Démarrez l'interpréteur Python en mode interactif et vérifiez-le. (Partiellement formé pour la lisibilité)
[.../module-experiments]$ python
Python 3.8.2 (default, Apr 18 2020, 18:08:23)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print(__name__)
__main__
>>> import m
>>> sys.modules['m']
<module 'm' from '.../module-experiments/m.py'>
>>> m
<module 'm' from '.../module-experiments/m.py'>
>>> m.f
<function f at 0x108452b80>
>>> m.C
<class 'm.C'>
Vous pouvez voir que le module immédiatement après le démarrage est __main__
.
Vous pouvez également voir qu'en important «m», vous pouvez accéder à «m», «m.f» et «m.C».
Le module importé est mis en cache dans l'espace de noms local. Par conséquent, comme tout autre nom, un module importé dans une fonction n'est pas accessible par d'autres fonctions. Cependant, comme le cache est global, il est accessible.
Un package est comme un module, sauf que vous pouvez y rechercher et importer des sous-modules. En utilisant des packages, vous pouvez créer une structure hiérarchique de modules.
Le nom du module (ou package) sera alors quelque chose comme ʻa.b.c séparé par des points. En important le module ʻa.b.c
avec ʻimport a.b.c`
--Module d'importation (package) ʻa --Importer le sous-module (package)
b (ʻa.b
) dans l'espace de noms du module ʻa --Importer le sous-module
c (ʻa.b.c
) dans l'espace de noms du module ʻa.b`
Cela vous permet d'accéder au module ʻa.b.c avec ʻa.b.c
.
** Remarque: vous ne pourrez pas y accéder avec c
. ** **
De plus, cette règle montre que les packages et les modules peuvent être importés de la même manière.
Bien sûr, vous ne pouvez pas accéder à ʻa.d ou ʻa.d.e
immédiatement après avoir importé ʻa.b.c. Si vous faites ʻimport a.d.e
ici, ʻa` existe dans le cache, donc
--Importer le sous-module (package) d
(ʻa.d) dans l'espace de noms du module ʻa
--Importer le sous-module ʻe (ʻa.d.e
) dans l'espace de noms du module ʻa.d`
Cela n'arrive que, donc à ces points, le module est initialisé.
Techniquement, un package est un module qui a l'attribut __path__
.
Cet attribut est utilisé lors de la recherche de sous-packages.
En d'autres termes, dans ʻimport a.b.c`,
--Trouver ʻa dans
sys.path et importer --Trouver et importer ʻa.b
depuis ʻa .__ path__ dans l'espace de noms du module ʻa
--Trouver et importer ʻa.b.c depuis ʻa.b .__ path__
dans l'espace de noms du module ʻa.b`
Cela se produit.
Notez que le module contenant le package a l'attribut __name__
.
Pour les modules importés, cette valeur est le nom complet du module (tel que ʻa.b.c`).
Puisqu'un package est un module, il peut être importé avec l'instruction d'importation comme un module.
import ... as ...
Si l'instruction d'importation a une clause ʻas, le module importé lui-même est lié au nom ci-dessous ʻas
.
Par exemple, ʻimport a.b as b vous permet d'accéder au module ʻa.b
directement avec le nom b
.
A ce moment, puisque le module ʻa est chargé et initialisé, les informations sur le module ʻa
(et, bien sûr, ʻa.b) sont mises en cache. Cependant, ʻa
n'est pas lié à l'espace de noms.
>>> import sys
>>> import a.b as b
['/Users/shinsa/git/python-experiments/module-experiments/a']
a
>>> sys.modules['a']
<module 'a' from '/Users/shinsa/git/python-experiments/module-experiments/a/__init__.py'>
>>> sys.modules['a.b']
<module 'a.b' from '/Users/shinsa/git/python-experiments/module-experiments/a/b/__init__.py'>
>>> b
<module 'a.b' from '/Users/shinsa/git/python-experiments/module-experiments/a/b/__init__.py'>
>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
Le nom du module vient immédiatement après ʻimport, et vous ne pouvez pas utiliser le nom défini à cet endroit. Par conséquent, juste parce que ʻimport a.b as b
est utilisé, ʻimport a.b.c ne peut pas être écrit comme ʻimport b.c
.
from
Cette forme d'importation prend le cas de «from a.b import c». c
peut être un module, un package ou un nom.
Le traitement suivant est effectué.
--Importer ʻa.b`. Cependant, le nom n'est pas lié.
c
est un module ou un package, importez ʻa.b.c (mais ne liez pas le nom) et liez ʻa.b.c
au nom c
.Si la clause ʻasest spécifiée, au lieu de lier
c dans l'exemple ci-dessus, elle est liée au nom spécifié dans la clause ʻas
.
from ... import *
Si le nom à importer est *
, c'est-à-dire from M import *
, alors dans le module M
M
qui ne commencent pas par _
Sont tous liés dans l'espace de noms actuel.
Dans l'instruction from ... import ...
, vous pouvez utiliser des représentations de package relatives dans la clause from
.
Par exemple, dans le script d'initialisation du package ʻa.b, ou dans le script du module ʻa.b.c
de ..
signifie "a partir d'un"
-- de .d
est de a.d
,Représentez chacun. Vous pouvez avoir plus de points.
PEP 366
Les calculs relatifs des packages étaient basés sur l'attribut «name».
Ensuite, par exemple, lorsque vous démarrez l'interpréteur avec python -m a.b.c
, ʻa / b / c.py fonctionne comme un module
main`.
Pour cette raison, il y avait un problème qui, par exemple, «a.b.d» ne pouvait pas être importé relativement.
Les nouvelles versions de Python calculent désormais les importations relatives en fonction de l'attribut __package__
, ce qui résout le problème de temps d'appel ci-dessus (PEP 366). Cependant, si vous le démarrez avec python <chemin> / a / b / c.py
, vous devez définir les attributs manuellement.
Jusqu'à présent, nous avons parlé des modules, des packages et de __path__
de manière abstraite.
En d'autres termes, je ne parle pas du tout d'un système de fichiers spécifique.
Dans les versions récentes, le système d'importation de Python est devenu un système très abstrait et puissant.
Par défaut, le système d'importation fonctionne sur un système de fichiers.
Par défaut, les modules sont représentés par des fichiers .py
et les packages par des répertoires.
Les détails sont les suivants et on peut voir que cela correspond à la structure de données abstraite jusqu'à présent.
sys.path
est supposé être le chemin du fichier et recherché. ʻImport m recherche les répertoires contenus dans
sys.pathdans l'ordre, et
m.py dans l'un des répertoires est importé. --Le paquet ʻa.b
est chargé et initialisé en exécutant ʻa / b / __ init __. Py`. se font en exécutant ʻa / b / c.py
.Inversement, par exemple, un système d'importation basé sur URI peut être implémenté, et le mécanisme de découverte de service peut être implémenté à l'aide du système d'importation de Python.
La documentation Python est déroutante car les informations sont dispersées un peu partout. C'est toujours compréhensible si vous le faites pour éviter la duplication d'informations, Au lieu de cela, chaque élément d'information est subtilement dupliqué mais dispersé. De plus, certaines informations sont obsolètes.
Recommended Posts