Je veux hériter d'une classe dans un fichier qui se trouve dans un répertoire au-dessus du répertoire actuel.
Est-il possible d'importer relativement ce fichier?
la source
Je veux hériter d'une classe dans un fichier qui se trouve dans un répertoire au-dessus du répertoire actuel.
Est-il possible d'importer relativement ce fichier?
from ..subpkg2 import mod
Selon les documents Python: lorsque vous êtes dans une hiérarchie de packages, utilisez deux points, comme le dit la déclaration d'importation doc:
Lorsque vous spécifiez le module à importer, vous n'avez pas besoin de spécifier le nom absolu du module. Lorsqu'un module ou un package est contenu dans un autre package, il est possible d'effectuer une importation relative dans le même package supérieur sans avoir à mentionner le nom du package. En utilisant des points de début dans le module ou le package spécifié après,
from
vous pouvez spécifier la hauteur à parcourir dans la hiérarchie de packages actuelle sans spécifier de noms exacts. Un point en tête signifie le package actuel où le module effectuant l'importation existe. Deux points signifient un niveau de package . Trois points représentent deux niveaux, etc. Donc, si vous exécutez àfrom . import mod
partir d'un module dupkg
package, vous finirez par importerpkg.mod
. Si vous exécutezfrom ..subpkg2 import mod
de l'intérieur,pkg.subpkg1
vous importerezpkg.subpkg2.mod
. La spécification des importations relatives est contenue dans le PEP 328 .
Le PEP 328 traite des importations absolues / relatives.
la source
La réponse de @ gimel est correcte si vous pouvez garantir la hiérarchie des packages qu'il mentionne. Si vous ne pouvez pas - si votre besoin réel est tel que vous l'avez exprimé, exclusivement lié aux répertoires et sans aucune relation nécessaire avec l'empaquetage - alors vous devez travailler
__file__
pour trouver le répertoire parent (quelquesos.path.dirname
appels suffiront; -), puis (si ce répertoire n'est pas déjàsys.path
activé) ajoutez provisoirement ledit répertoire au tout début desys.path
,__import__
supprimez à nouveau ledit répertoire - un travail compliqué en effet, mais, "quand vous le devez, vous devez" (et Pyhon s'efforce de n'arrêtez jamais le programmeur de faire ce qui doit être fait - comme le dit la norme ISO C dans la section "Spirit of C" dans sa préface! -).Voici un exemple qui peut vous convenir:
la source
sys.path
rendre ainsi le même module disponible sous des noms différents et tous les bogues correspondants. autopath.py dans pypy ou _preamble.py dans twisted le résoudre en utilisant un critère de recherche qui identifie le package de niveau supérieur tout en parcourant les répertoires vers le haut.sys.path.remove(pathYouJustAdded)
après l'importation dont vous aviez besoin afin de ne pas conserver ce nouveau chemin.Importez le module à partir d'un répertoire qui se trouve exactement un niveau au-dessus du répertoire actuel:
la source
from .. import module
j'ai obtenu l'erreur ValueError: tentative d'importation relative dans un non-package en suivant la recommandationComment charger un module qui est un répertoire
préface: J'ai fait une réécriture substantielle d'une réponse précédente dans l'espoir d'aider les gens à pénétrer l'écosystème de python et, espérons-le, de donner à chacun le meilleur changement de succès avec le système d'importation de python.
Cela couvrira les importations relatives au sein d'un package , ce qui, je pense, est le cas le plus probable de la question d'OP.
Python est un système modulaire
C'est pourquoi nous écrivons
import foo
pour charger un module "foo" depuis l'espace de noms racine, au lieu d'écrire:Python n'est pas couplé à un système de fichiers
C'est pourquoi nous pouvons intégrer python dans un environnement où il n'y a pas de système de fichiers de facto sans en fournir un virtuel, tel que Jython.
Le découplage d'un système de fichiers permet aux importations d'être flexibles, cette conception permet des choses comme les importations à partir de fichiers archive / zip, l'importation de singletons, la mise en cache de bytecode, les extensions cffi, même le chargement de définition de code à distance.
Donc, si les importations ne sont pas couplées à un système de fichiers, que signifie "un répertoire vers le haut"? Nous devons sélectionner quelques heuristiques mais nous pouvons le faire, par exemple lorsque vous travaillez dans un package , certaines heuristiques ont déjà été définies qui rendent les importations relatives similaires
.foo
et..foo
fonctionnent dans le même package. Cool!Si vous souhaitez sincèrement coupler vos modèles de chargement de code source à un système de fichiers, vous pouvez le faire. Vous devrez choisir votre propre heuristique et utiliser une sorte de machinerie d'importation, je recommande importlib
L'exemple d'importlib de Python ressemble à ceci:
Emballage
Il y a un grand exemple de projet disponible officiellement ici: https://github.com/pypa/sampleproject
Un package python est une collection d'informations sur votre code source, qui peut indiquer à d'autres outils comment copier votre code source sur d'autres ordinateurs et comment intégrer votre code source dans le chemin d'accès de ce système afin qu'il
import foo
fonctionne pour d'autres ordinateurs (quel que soit l'interpréteur, système d'exploitation hôte, etc.)Structure du répertoire
Permet d'avoir un nom de package
foo
, dans un répertoire (de préférence un répertoire vide).Ma préférence est de créer en
setup.py
tant que frèrefoo.py
, car cela rend l'écriture du fichier setup.py plus simple, mais vous pouvez écrire la configuration pour changer / rediriger tout ce que setuptools fait par défaut si vous le souhaitez; par exemple, placerfoo.py
sous un répertoire "src /" est quelque peu populaire, non couvert ici..
.
"editable" aka
-e
redirigera à nouveau la machine d'importation pour charger les fichiers source dans ce répertoire, au lieu de copier les fichiers exacts actuels dans la bibliothèque de l'environnement d'installation. Cela peut également provoquer des différences de comportement sur la machine d'un développeur, assurez-vous de tester votre code! Il existe des outils autres que pip, mais je recommanderais pip comme introduction :)J'aime aussi faire
foo
un "package" (un répertoire contenant__init__.py
) au lieu d'un module (un seul fichier ".py"), les "packages" et les "modules" peuvent être chargés dans l'espace de noms racine, les modules permettent des espaces de noms imbriqués, ce qui est utile si nous voulons avoir une importation "relative d'un répertoire vers le haut"..
J'aime aussi faire un
foo/__main__.py
, cela permet à python d'exécuter le package en tant que module, par exemplepython3 -m foo
s'exécutera enfoo/__main__.py
tant que__main__
..
Permet d'étoffer cela avec quelques modules supplémentaires: Fondamentalement, vous pouvez avoir une structure de répertoire comme ceci:
setup.py
contient classiquement des informations de métadonnées sur le code source, telles que:foo
, bien que le remplacement des traits de soulignement par des tirets soit populairepython ./setup.py test
Son très vaste, il peut même compiler des extensions c à la volée si un module source est installé sur une machine de développement. Pour un exemple quotidien, je recommande setup.py du référentiel d'échantillons PYPA.
Si vous publiez un artefact de génération, par exemple une copie du code destiné à exécuter des ordinateurs presque identiques, un fichier requirements.txt est un moyen populaire de prendre des instantanés des informations de dépendance exactes, où "install_requires" est un bon moyen de capturer le minimum et versions compatibles maximum. Cependant, étant donné que les machines cibles sont de toute façon presque identiques, je recommande fortement de créer un tarball d'un préfixe python entier. Cela peut être délicat, trop détaillé pour entrer ici. Consultez
pip install
l'--target
option de, ou virtualenv aka venv pour les pistes.retour à l'exemple
comment importer un fichier d'un répertoire vers le haut:
De foo / spam / eggs.py, si nous voulions du code de foo / baz, nous pourrions le demander par son espace de noms absolu:
Si nous voulions réserver la capacité de déplacer eggs.py dans un autre répertoire à l'avenir avec une autre
baz
implémentation relative , nous pourrions utiliser une importation relative comme:la source
Python est un système modulaire
Python ne repose pas sur un système de fichiers
Pour charger le code python de manière fiable, ayez ce code dans un module et ce module installé dans la bibliothèque de python.
Les modules installés peuvent toujours être chargés à partir de l'espace de noms de niveau supérieur avec
import <name>
Il y a un grand exemple de projet disponible officiellement ici: https://github.com/pypa/sampleproject
Fondamentalement, vous pouvez avoir une structure de répertoires comme celle-ci:
.
Assurez - vous de déclarer votre
setuptools.setup()
danssetup.py
,exemple officiel: https://github.com/pypa/sampleproject/blob/master/setup.py
Dans notre cas, nous voulons probablement exporter
bar.py
etfoo/__init__.py
, mon bref exemple:setup.py
.
Nous pouvons maintenant installer notre module dans la bibliothèque python; avec pip, vous pouvez installer
the_foo_project
dans votre bibliothèque python en mode édition, afin que nous puissions y travailler en temps réel.
Maintenant, à partir de n'importe quel contexte python, nous pouvons charger nos py_modules et packages partagés
foo_script.py
la source
pip install --edit foo
, presque toujours à l'intérieur d'un virtualenv. Je n'écris presque jamais un module qui n'est pas destiné à être installé. si je comprends mal quelque chose que j'aimerais savoir.editable
les liens d'oeufs et les modules python installés ne sont pas exactement les mêmes à tous points de vue; par exemple, l'ajout d'un nouvel espace de noms à un module modifiable se trouvera dans votre recherche de chemin, mais s'il n'est pas exporté dans votre fichier setup.py, il ne sera pas empaqueté / installé! Testez votre cas d'utilisation :)