web-dev-qa-db-fra.com

Comment récupérer le chemin d'un module?

Je veux détecter si le module a changé. Maintenant, utiliser inotify est simple, il vous suffit de connaître le répertoire dans lequel vous souhaitez recevoir les notifications.

Comment récupérer le chemin d'un module en python?

664
Cheery
import a_module
print(a_module.__file__)

Vous donnera en fait le chemin du fichier .pyc qui a été chargé, du moins sur Mac OS X. Donc je suppose que vous pouvez faire:

import os
path = os.path.abspath(a_module.__file__)

Vous pouvez aussi essayer:

path = os.path.dirname(a_module.__file__)

Pour obtenir le répertoire du module.

781
orestis

Il existe un module inspect en python.

documentation officielle

Le module inspect fournit plusieurs fonctions utiles pour vous aider à obtenir des informations sur les objets en direct tels que les modules, les classes, les méthodes, les fonctions, les traces, les objets frame et les objets code. Par exemple, il peut vous aider à examiner le contenu d'une classe, à récupérer le code source d'une méthode, à extraire et formater la liste d'arguments d'une fonction ou à obtenir toutes les informations dont vous avez besoin pour afficher un suivi détaillé.

Exemple:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'
232
SummerBreeze

Comme d'autres réponses l'ont dit, le meilleur moyen de le faire est avec __file__ (démontré ci-dessous). Cependant, il y a une mise en garde importante, à savoir que __file__ n'existe PAS si vous exécutez le module seul (c'est-à-dire en tant que __main__).

Par exemple, supposons que vous ayez deux fichiers (qui se trouvent tous deux sur votre PYTHONPATH):

#/path1/foo.py
import bar
print(bar.__file__)

et

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

Lancer foo.py donnera le résultat:

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

CEPENDANT, si vous essayez d’exécuter bar.py seul, vous obtiendrez:

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

J'espère que cela t'aides. Cette mise en garde m'a coûté beaucoup de temps et de confusion lors du test des autres solutions présentées.

66
mcstrother

Je vais essayer d’aborder quelques variations sur cette question également:

  1. trouver le chemin du script appelé
  2. trouver le chemin du script en cours d'exécution
  3. trouver le répertoire du script appelé

(Certaines de ces questions ont été posées sur SO, mais ont été fermées en double et redirigées ici.)

Mises en garde concernant l'utilisation de __file__

Pour un module que vous avez importé:

import something
something.__file__ 

renverra le chemin absolu du module. Cependant, étant donné le script suivant foo.py:

#foo.py
print '__file__', __file__

L'appeler avec 'python foo.py' retournera simplement 'foo.py'. Si vous ajoutez un shebang:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

et appelez-le en utilisant ./foo.py, il retournera './foo.py'. L'appeler depuis un répertoire différent (par exemple, mettre foo.py dans la barre de répertoires), puis

python bar/foo.py

ou en ajoutant un Shebang et en exécutant le fichier directement:

bar/foo.py

retournera 'bar/foo.py' (le chemin relatif ).

Trouver le répertoire

Maintenant, à partir de là pour obtenir le répertoire, os.path.dirname(__file__) peut également être délicat. Au moins sur mon système, il renvoie une chaîne vide si vous l'appelez à partir du même répertoire que le fichier. ex.

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

affichera:

__file__ is: foo.py
os.path.dirname(__file__) is: 

En d’autres termes, il renvoie une chaîne vide. Cela ne semble donc pas fiable si vous souhaitez l’utiliser pour le fichier actuel (par opposition à fichier d'un module importé). Pour résoudre ce problème, vous pouvez l'envelopper dans un appel à abspath:

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

qui produit quelque chose comme:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

Notez que abspath () ne résout PAS les liens symboliques. Si vous voulez faire cela, utilisez realpath () à la place. Par exemple, créer un lien symbolique file_import_testing_link pointant sur file_import_testing.py, avec le contenu suivant:

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

l’exécution imprimera des chemins absolus comme:

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link -> file_import_testing.py

En utilisant inspect

@SummerBreeze mentionne l'utilisation du module inspect .

Cela semble bien fonctionner, et est assez concis, pour les modules importés:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

renvoie docilement le chemin absolu. Cependant, pour trouver le chemin du script en cours d'exécution, je n'ai pas trouvé de moyen de l'utiliser.

36
jpgeek

Je ne comprends pas pourquoi personne ne parle de cela, mais pour moi la solution la plus simple consiste à imp.find_module ("modulename") (documentation - ici ):

import imp
imp.find_module("os")

Il donne un tuple avec le chemin en deuxième position:

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

L'avantage de cette méthode par rapport à la méthode "inspecter" est qu'il n'est pas nécessaire d'importer le module pour le faire fonctionner et que vous pouvez utiliser une chaîne en entrée. Utile lors de la vérification de modules appelés dans un autre script par exemple.

EDIT:

En python3, le module importlib devrait faire:

Doc de importlib.util.find_spec:

Renvoie la spécification du module spécifié.

Tout d'abord, sys.modules est vérifié pour voir si le module a déjà été importé. Si tel est le cas, sys.modules [nom]. spec est renvoyé. Si ce paramètre est défini sur Aucun, ValueError est déclenché. Si le module ne se trouve pas dans sys.modules, sys.meta_path recherche une spécification appropriée avec la valeur de 'path' donnée aux chercheurs. Aucun n'est retourné si aucune spécification n'a pu être trouvée.

Si le nom est pour le sous-module (contient un point), le module parent est automatiquement importé.

Le nom et les arguments du paquet fonctionnent de la même façon que importlib.import_module (). En d'autres termes, les noms de modules relatifs (avec les points principaux) fonctionnent.

29
PlasmaBinturong

C'était trivial.

Chaque module a une variable __file__ qui indique son chemin relatif depuis l'endroit où vous vous trouvez.

Par conséquent, obtenir un répertoire pour que le module le notifie est simple comme suit:

os.path.dirname(__file__)
19
Cheery
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
17
vinoth

Utilitaire de ligne de commande

Vous pouvez le modifier en un utilitaire de ligne de commande,

python-which <package name>

enter image description here


Créer /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

Le rendre exécutable

Sudo chmod +x /usr/local/bin/python-which
9
Jossef Harush
import module
print module.__path__

Les packages prennent en charge un attribut spécial supplémentaire, __path__. Ceci est initialisé pour être une liste contenant le nom du répertoire contenant le __init__.py du paquet avant l'exécution du code de ce fichier. Cette variable peut être modifiée. Cela affecterait les futures recherches de modules et de sous-packages contenus dans le package.

Bien que cette fonctionnalité ne soit pas souvent nécessaire, elle peut être utilisée pour étendre l’ensemble des modules contenus dans un package.

Source

8
Lukas Greblikas

J'ai donc passé pas mal de temps à essayer de le faire avec py2exe. Le problème était de récupérer le dossier de base du script, qu'il soit exécuté en tant que script python ou en tant que fichier exécutable py2exe. Pour que cela fonctionne également, qu'il soit exécuté à partir du dossier actuel, d'un autre dossier ou (c'est le cas le plus difficile) du chemin du système.

Finalement, j'ai utilisé cette approche, en utilisant sys.frozen comme indicateur de l'exécution dans py2exe:

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))
7
uri

vous pouvez simplement importer votre module puis appuyez sur son nom et vous obtiendrez son chemin d'accès complet

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>
5
Hassan Ashraf

Si le seul inconvénient lié à l'utilisation de __file__ concerne le répertoire actuel, le répertoire relatif est vide (c.-à-d. Lorsqu'il est exécuté en tant que script à partir du même répertoire que le script), la solution suivante est triviale:

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

Et le résultat:

$ python teste.py 
teste.py . /home/user/work/teste

L'astuce est dans or '.' après l'appel dirname(). Il définit le répertoire comme ., ce qui signifie répertoire actuel et constitue un répertoire valide pour toute fonction liée au chemin.

Ainsi, utiliser abspath() n'est pas vraiment nécessaire. Mais si vous l'utilisez quand même, l'astuce n'est pas nécessaire: abspath() accepte les chemins vierges et les interprète correctement comme le répertoire en cours.

3
MestreLion

J'aimerais contribuer avec un scénario commun (dans Python 3) et explorer quelques approches.

La fonction intégrée open () accepte le chemin relatif ou absolu comme premier argument. Le chemin relatif est traité comme par rapport au répertoire de travail en cours bien qu'il soit recommandé de passer le chemin absolu au fichier.

Simplement dit, si vous exécutez un fichier de script avec le code suivant, il est pas garanti que le fichier example.txt sera créé dans le même répertoire où se trouve le fichier script:

with open('example.txt', 'w'):
    pass

Pour corriger ce code, nous devons obtenir le chemin du script et le rendre absolu. Pour que le chemin soit absolu, nous utilisons simplement la fonction os.path.realpath () . Pour obtenir le chemin d'accès au script, plusieurs fonctions courantes renvoient différents résultats:

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

Les deux fonctions os.getcwd () et os.path.realpath () renvoient les résultats du chemin d'accès en fonction du répertoire de travail actuel. Généralement pas ce que nous voulons. Le premier élément de la liste sys.argv est le chemin du script racine (le script que vous exécutez), que vous appeliez la liste dans le script racine lui-même ou dans l'un de ses modules. Cela peut être utile dans certaines situations. La variable _ FILE _ contient le chemin du module à partir duquel elle a été appelée.


Le code suivant crée correctement un fichier example.txt dans le même répertoire que le script:

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass
3
Jeyekomon

À partir des modules d'un package python, je devais faire référence à un fichier résidant dans le même répertoire que package. Ex.

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

Donc ci-dessus, j'ai dû appeler maincli.py à partir du module my_lib_a.py, sachant que top_package et maincli.py se trouvent dans le même répertoire. Voici comment j'obtiens le chemin vers maincli.py:

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

Basé sur l'affichage de PlasmaBinturong, j'ai modifié le code.

1
Al Conrad

Si vous souhaitez le faire dynamiquement dans un "programme", essayez ce code:
Mon problème est que vous ne connaissez peut-être pas le nom exact du module pour le "coder en dur". Il peut être sélectionné dans une liste ou ne pas être en cours d'exécution pour utiliser __file__.

(Je sais, cela ne fonctionnera pas dans Python 3)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

J'ai essayé de me débarrasser du problème "global" mais j'ai trouvé des cas où cela ne fonctionnait pas. Je pense que "execfile ()" peut être imité dans Python 3. Comme c'est dans un programme, dans une méthode ou un module pour la réutilisation.

1
Robin Randall

Si vous souhaitez connaître le chemin absolu de votre script, vous pouvez utiliser Path object:

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

méthode cwd ()

Retourne un nouvel objet chemin représentant le répertoire en cours (tel que retourné par os.getcwd ())

méthode resolve)

Rendre le chemin absolu, en résolvant les liens symboliques. Un nouvel objet de chemin est renvoyé:

1
Vlad Bezden

Si vous souhaitez récupérer le chemin racine du package à partir de l'un de ses modules, les opérations suivantes (testées sur Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

Le chemin principal __init__.py peut également être référencé en utilisant __file__.

J'espère que cela t'aides!

0
fr_andres