Paquets et modules Python

ChangeLog

--2020-04-18: Correction du comportement dans le module __main__.

Aperçu

Jetons un coup d'œil aux packages et modules Python, que de nombreuses personnes semblent comprendre et utiliser. Ce n'est pas très organisé, je vais donc le réécrire un jour.

Motivation

J'ai du code d'apprentissage automatique Python écrit par quelqu'un d'autre. Il y a un fichier que vous voulez exécuter à l'emplacement . / A / b / c.py du répertoire courant. Ce fichier est écrit dans un format courant qui fonctionne de deux manières selon la valeur de «name». À l'intérieur, . / A / b / d.py est ** absolument importé ** par ʻimport d`.

À ce stade, en supposant que PYTHONPATH est laissé par défaut, lequel fonctionne correctement quand il est réglé sur python. / A / b / c.py ou quand il est réglé sur ʻimport abcà partir d'un autre fichier python. Changera. Si ce dernier ne fonctionne pas lorsque le premier fonctionne, et que le second fonctionne, si vous réécrivezc.py` en importation relative, le premier ne fonctionnera pas. Ce qui se passe, c'est la motivation pour étudier cette fois.

Permettez-moi d'expliquer un peu plus cette dernière situation. Vous exécutez pytest ./test/<test file> .py ou python -m pytest ./test/ <test file> .py pour les tests unitaires. Le fait est que le fichier de test n'est pas dans le répertoire courant.

Les références

J'ai parcouru la version v3.8.2 des deux.

Module = fichier

Notez que le didacticiel lit les fichiers de niveau supérieur, c'est-à-dire les fichiers lancés par python <file> en tant que ** scripts **.

Importateur

Le plus simple

Je comprends.

Côté importé

Chemin de recherche du module (sys.path)

Dans l'exemple ci-dessus, le module m à importer, c'est-à-dire le fichier m.py, se trouve au début de la liste des répertoires définie sur sys.path (la valeur de la variable path du module sys). Il est recherché dans l'ordre de. Par défaut, ils sont classés dans l'ordre suivant:

  1. Répertoire avec ** Script **, répertoire courant s'il n'est pas spécifié (par exemple, lorsqu'une session interactive a été exécutée par python)
  2. La valeur de la variable d'environnement PYTHONPATH
  3. Par défaut pour chaque installation (probablement le répertoire dans lequel la bibliothèque est installée par pip, etc.)

Ici, le premier est l'auteur-compositeur **, le répertoire contenant le fichier exécuté est recherché à la place du répertoire courant. ** ** Les deux sont identiques uniquement si vous exécutez le fichier dans le répertoire courant.

Résoudre l'exemple donné dans "Motivation" (1)

Maintenant, la raison du problème que j'ai écrit dans "Motivation" est presque claire. Si vous exécutez python. / A / b / c.py avec l'ancienne méthode, la première règle place. / A / b au début de sys.path. Ensuite, ʻimport dest d'abord recherché pour ce répertoire, et l'importation réussit car il a en fait. / A / b / d.py`.

D'autre part, lorsque pytest est exécuté, sys.path commence par. / Test, donc ʻimport abc ne passe pas en premier lieu, et même si cela est évité en définissant PYTHONPATH, c ʻImport d dans .py ne passe pas cette fois.

Si ʻimport dest changé enfrom .import d` (est-ce que c'était?) Et ** importation relative **, l'ancien modèle ne passera certainement pas [confirmation requise].

Anti-motif sys.path

Si la structure de répertoires du module est compliquée, ou si vous essayez de réaliser une importation dynamique,

On dit que ** est un mauvais coup ** [Source]. Il semble correct d'utiliser pleinement ʻimportlib`.

Package = répertoire

Un ** package ** est une collection des modules ci-dessus dans un répertoire. Le nom du répertoire devient le nom du package. Les répertoires peuvent avoir une structure hiérarchique, qui correspond au chemin du package (séquence de noms de packages séparés par des points).

Importateur

--ʻImport a.b.cimporte le modulec du package ʻa.b. Autrement dit, importez «a / b / c.py» dans le répertoire cible de recherche du module.

De là, beaucoup de gens semblent ne le comprendre que d'une manière ou d'une autre. Je le suis aussi.

Côté importé

Lorsque le package «p» est importé, la variable «path» dans «p / __ init __. Py» peut faire référence à la chaîne représentant le répertoire de «p».

Instruction from ... import ...

Si vous importez le paquet b comme ci-dessus, b / __ init __. Py sera exécuté. Ce fichier est vide par défaut, et quand il est vide, l'interpréteur ne fait rien, donc importer ** b ne rend pas ʻa.b.c` accessible. ** **

Importation relative du module importé

Lors de l'importation d'autres modules, l'importation absolue mentionnée ci-dessus est généralement utilisée. La recherche des modules se fait pour sys.path. Vous pouvez ** importer relative ** en utilisant l'instruction from import ci-dessus.

Dans le module importé (c'est-à-dire le fichier .py)

Vous pouvez importer des packages, des modules, des noms, etc. les uns par rapport aux autres. À ce stade, . et .. sont résolus en fonction du ** chemin du package ** où le module actuel existe. Autrement dit, si le module actuel est ʻa.b.m, c'est-à-dire que le package auquel il appartient est ʻa.b, alors . est ʻa.b et .. est ʻa.

Notez que le module __main__ n'a pas de chemin de package. Une conséquence importante de ceci est que vous ne pouvez pas effectuer d'importations relatives à partir de modules exécutés en tant que ** __main__. ** **

De plus, je pense que c'est correct de faire quelque chose comme ʻimport ..p.q.m`, mais il semble que cela ne peut pas être fait

Résoudre l'exemple donné dans "Motivation" (2)

Cela résout la deuxième question. La réécriture de ʻa / b / c.pyen importation relative commefrom .import d fonctionne très bien si c est importé avec ʻimport abc, mais python a / Lorsqu'il est exécuté en tant que b / c.py, c.py se comporte comme module __main__ et l'importation relative n'est pas disponible. En conséquence, j'ai été déçu du comportement.

De plus, en conséquence, les modules importés à partir du code que vous souhaitez utiliser à la fois comme scripts et comme modules, tels que «a / b / c.py» dans l'exemple, doivent être «pip install». De cette façon, vous pouvez toujours utiliser l'importation absolue, vous pouvez donc utiliser l'une ou l'autre méthode.

Les questions non résolues

Il a également été confirmé que le comportement d'importation diffère selon la façon dont pytest est démarré. J'ai essayé de mettre une instruction d'impression dans le script de test (-s est une option pour empêcher pytest de capturer la sortie standard)

--pytest -s test / <fichier de test.py> démarre sys.path avec le répertoire test, suivi des valeurs par défaut du système --Mais si vous faites python -m pytest -s test / <test file.py>, la chaîne vide " " est ajoutée après le répertoire test. Cela signifie peut-être le répertoire actuel.

Certaines des raisons à cela sont également connues. Si vous spécifiez un module avec -m lors du démarrage de l'interpréteur Python, le répertoire courant est ajouté au début de sys.path. Dans ce cas, c'est peut-être pytest, pas l'interpréteur, qui ajoute «test» à «sys.path». Parce que dans ce cas, -s test / <test file.py> est juste un argument, pas le nom du script à exécuter [examine]. De plus, lorsque vous installez la commande avec pip, vérifiez les paramètres tels que sys.path lorsque vous lancez la commande.

à la fin

Toute erreur est la bienvenue.

Recommended Posts

Paquets et modules Python
Apprenez à connaître les packages et les modules Python
Cours de base Python (14 modules et packages)
Organisez les modules et les packages Python dans le désordre
Obtenez une compréhension abstraite des modules et des packages Python
Paquets qui gèrent le MIDI avec Python midi et pretty_midi
A propos des modules Python Primer et des expressions conditionnelles
Environnement virtuel Python et packages sur Ubuntu
[Python] Empaquetez et distribuez vos propres modules
[python] Compresser et décompresser
Liste des modules python
Astuces Python et Numpy
[Python] pip et roue
Itérateur et générateur Python
Intégration Vue-Cli et Python
Ruby, Python et carte
entrée et sortie python
Utilisation des packages Python #external
Python et Ruby se séparent
Python asyncio et ContextVar
Python - Explication et résumé de l'utilisation des 24 meilleurs packages
Gérez les packages d'exécution Python et les packages d'environnement de développement avec Poetry
Programmation avec Python et Tkinter
Chiffrement et déchiffrement avec Python
Python: variables de classe et d'instance
3-3, chaîne Python et code de caractère
Série Python 2 et série 3 (édition Anaconda)
Python et matériel - Utilisation de RS232C avec Python -
Python sur Ruby et Ruby en colère sur Python
Indentation Python et format de chaîne
[Python] Chargement de modules personnalisés à plusieurs niveaux
division des nombres réels python (/) et division des nombres entiers (//)
Installez Python et Flask (Windows 10)
À propos des objets et des classes Python
À propos des variables et des objets Python
Apache mod_auth_tkt et Python AuthTkt
Å (Ongustorome) et NFC @ Python
# 2 [python3] Séparation et commentaire
Copie superficielle Python et copie profonde
Mémo tranche python et rubis
Installation de Python et grammaire de base
J'ai comparé Java et Python!
Copie superficielle Python et copie profonde
À propos de Python, len () et randint ()
À propos de la date et du fuseau horaire Python
Installez Python 3.7 et Django 3.0 (CentOS)
Construction d'environnement Python et TensorFlow
Variables de classe et d'instance Python
Feuille de route pour la publication de packages Python
Syntaxe Ruby et Python ~ branch ~
[Python] Python et sécurité-① Qu'est-ce que Python?
Pile et file d'attente en Python
métaclasse python et déclaration sqlalchemy
Implémentation de Fibonacci et des nombres premiers (python)
bases de python: conditions et itérations
Opérateur de bits Python et somme logique
[Note] Classes, modules, packages, bibliothèques
Module de débogage et de test Python