Wie kann ich den Pfad eines Moduls abrufen?


755

Ich möchte feststellen, ob sich das Modul geändert hat. Die Verwendung von inotify ist jetzt einfach. Sie müssen nur noch das Verzeichnis kennen, aus dem Sie Benachrichtigungen erhalten möchten.

Wie rufe ich den Pfad eines Moduls in Python ab?


1
Überprüfen Sie Modulfinder: docs.python.org/library/modulefinder.html

9
Wenn Sie immer noch auf dieser Website suchen, aktualisieren Sie bitte die richtige Antwort darauf . Es ist viel sauberer als die vorgeschlagene Lösung und funktioniert auch in Fällen, in denen __file__es nicht festgelegt ist.
Erikbwork

3
@ erikb85: es ist nicht nur sauberer; inspect-basierte Lösung funktioniert auch für den execfile()Fall, dass im __file__Stillen ein falscher Name erzeugt wird.
JFS


import pathlib, module; pathlib.Path(module.__file__).resolve().parentDies ist plattformunabhängig
MortenB

Antworten:


906
import a_module
print(a_module.__file__)

Gibt Ihnen tatsächlich den Pfad zu der .pyc-Datei, die geladen wurde, zumindest unter Mac OS X. Sie können also Folgendes tun:

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

Sie können auch versuchen:

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

Um das Verzeichnis des Moduls abzurufen.


54
Hier erfahren Sie, wie Sie den Pfad des zu importierenden Moduls abrufen, jedoch nicht des Moduls / Skripts, in dem Sie sich befinden (für das Skript, das Sie ausführen, __file__handelt es sich nicht um einen vollständigen Pfad, sondern um einen relativen Pfad). Für die Datei, in der ich mich befinde, musste ich ein anderes Modul aus demselben Verzeichnis importieren und wie hier gezeigt vorgehen. Kennt jemand einen bequemeren Weg?
Ben Bryant

5
@hbdgaf ziemlich sicher, dass es keinen eingebauten gibtself.__file__
Dan Passaro

26
@BenBryant @hbdgaf os.path.dirname(__file__)funktioniert gut für mich und gibt den abs-Pfad des Modulverzeichnisses zurück.
Niccolò

9
Ich habe versucht, dies zu tun und die Rückverfolgung zu erhalten: AttributeError: 'module' object has no attribute '__file__'
Dorian Dore

5
@DorianDore Ich habe ein wenig mit Modulen herumgespielt und bin zu einer Lösung gekommen path = module.__path__.__dict__["_path"][0], aber ich bin mir nicht sicher, ob es portabel ist oder ob es sich auch nicht zwischen Python-Versionen unterscheidet. Es funktioniert für mich, im Gegensatz zu dieser Antwort, die mir den gleichen Fehler gibt und die inspectAntwort erhöht TypeError: <module 'module' (namespace)> is a built-in module...
Jezor

279

Es gibt ein inspectModul in Python.

Offizielle Dokumentation

Das Inspect-Modul bietet verschiedene nützliche Funktionen, um Informationen zu Live-Objekten wie Modulen, Klassen, Methoden, Funktionen, Tracebacks, Frame-Objekten und Code-Objekten abzurufen. Sie können beispielsweise den Inhalt einer Klasse untersuchen, den Quellcode einer Methode abrufen, die Argumentliste für eine Funktion extrahieren und formatieren oder alle Informationen abrufen, die Sie zum Anzeigen eines detaillierten Tracebacks benötigen.

Beispiel:

>>> 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'

7
Sie können auch inspectden Namen der aktuellen Datei abrufen. siehe stackoverflow.com/a/50905/320036
z0r

5
Ich habe diese Frage viele Male gegoogelt und dies ist die vernünftigste Antwort, die ich je gesehen habe! Bitte aktualisieren Sie die Informationen überinspect.currentframe()
erikbwork

Der inspect.getfile()Ansatz funktioniert nicht mit dem Modul _io, sondern mit dem Modul io.
Smwikipedia

70

Wie die anderen Antworten bereits sagten, ist der beste Weg, dies zu tun, mit __file__(unten noch einmal gezeigt). Es gibt jedoch eine wichtige Einschränkung, die __file__NICHT besteht, wenn Sie das Modul alleine ausführen (dh als__main__ ).

Angenommen, Sie haben zwei Dateien (beide befinden sich auf Ihrem PYTHONPATH):

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

und

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

Wenn Sie foo.py ausführen, erhalten Sie folgende Ausgabe:

/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

Wenn Sie jedoch versuchen, bar.py alleine auszuführen, erhalten Sie:

/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 

Hoffe das hilft. Diese Einschränkung hat mich beim Testen der anderen vorgestellten Lösungen viel Zeit und Verwirrung gekostet.


5
In diesem Fall können Sie anstelle der Datei sys.argv [0] verwenden .
Jimothy

4
Ist das eine versionenspezifische Einschränkung? In 2.6 und 2.7 verlasse ich mich erfolgreich auf Datei , die Datei funktioniert, wenn Name __ == '__ main '. Der einzige Fehlerfall, den ich gesehen habe, ist "python -c 'print file '". Ich werde hinzufügen, dass die Datei manchmal '<stdin>' ​​sein kann, was passiert, wenn IDEs wie Emacs den aktuellen Puffer ausführen.
Paul Du Bois

1
Beachten Sie, dass führende und nachfolgende "__" -Zeichen ein Wort in Fettdruck setzen. Denken Sie also daran, wenn Sie die vorherigen Kommentare lesen :-P
Paul Du Bois

1
@PaulDuBois Sie können es mit Back-Tics umgeben: ` __file__` wird__file__
fncomp

1
Wie bekommst du das NameError? @ Paul Du Bois: Ich habe Python versucht 2,3-3,4 und __file__ist definiert aber ich Python - Datei ausführen: python a.py, python -ma, ./a.py.
JFS

43

Ich werde auch versuchen, einige Variationen dieser Frage anzugehen:

  1. Finden des Pfades des aufgerufenen Skripts
  2. Suchen des Pfads des aktuell ausgeführten Skripts
  3. Suchen des Verzeichnisses des aufgerufenen Skripts

(Einige dieser Fragen wurden auf SO gestellt, aber als Duplikate geschlossen und hier umgeleitet.)

Vorsichtsmaßnahmen bei der Verwendung __file__

Für ein Modul, das Sie importiert haben:

import something
something.__file__ 

gibt den absoluten Pfad des Moduls zurück. Angesichts des folgenden Skripts foo.py:

#foo.py
print '__file__', __file__

Wenn Sie es mit 'python foo.py' aufrufen, wird einfach 'foo.py' zurückgegeben. Wenn Sie einen Schebang hinzufügen:

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

und rufen Sie es mit ./foo.py auf, es wird './foo.py' zurückgeben. Rufen Sie es aus einem anderen Verzeichnis auf (z. B. foo.py in die Verzeichnisleiste einfügen) und rufen Sie dann eines der beiden auf

python bar/foo.py

oder einen Shebang hinzufügen und die Datei direkt ausführen:

bar/foo.py

gibt 'bar / foo.py' (den relativen Pfad) zurück.

Das Verzeichnis finden

Jetzt von dort aus das Verzeichnis zu bekommen, os.path.dirname(__file__)kann auch schwierig sein. Zumindest auf meinem System wird eine leere Zeichenfolge zurückgegeben, wenn Sie sie aus demselben Verzeichnis wie die Datei aufrufen. Ex.

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

wird ausgegeben:

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

Mit anderen Worten, es wird eine leere Zeichenfolge zurückgegeben, sodass dies nicht zuverlässig erscheint, wenn Sie es für die aktuelle Datei verwenden möchten (im Gegensatz zur Datei eines importierten Moduls). Um dies zu umgehen, können Sie es in einen Aufruf an abspath einwickeln:

# 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__))

welches etwas ausgibt wie:

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

Beachten Sie, dass abspath () Symlinks NICHT auflöst. Wenn Sie dies tun möchten, verwenden Sie stattdessen realpath (). Erstellen Sie beispielsweise einen Symlink file_import_testing_link, der auf file_import_testing.py verweist, mit dem folgenden Inhalt:

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

Beim Ausführen werden absolute Pfade wie folgt gedruckt:

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

file_import_testing_link -> file_import_testing.py

Mit inspizieren

@SummerBreeze erwähnt die Verwendung der Inspektion Modul.

Dies scheint für importierte Module gut zu funktionieren und ist recht prägnant:

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

gibt gehorsam den absoluten Pfad zurück. Um den Pfad des aktuell ausgeführten Skripts zu finden, habe ich jedoch keine Möglichkeit gefunden, es zu verwenden.


1
inspect.getfile (os) ist dasselbe wie os .__ file__ aus dem Code: def getfile (object): "" Ermitteln Sie, in welcher Quell- oder kompilierten Datei ein Objekt definiert wurde. "" if ismodule (object): if hasattr (Objekt, ' Datei '): Objekt zurückgeben .__ Datei__
idanzalz

4
Sie können verwenden inspect.getfile(inspect.currentframe()), um den Pfad des aktuell ausgeführten Skripts abzurufen.
Jbochi

33

Ich verstehe nicht, warum niemand darüber spricht, aber für mich ist die einfachste Lösung die Verwendung von imp.find_module ("Modulname") (Dokumentation) hier ):

import imp
imp.find_module("os")

Es gibt ein Tupel mit dem Pfad an zweiter Stelle:

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

Der Vorteil dieser Methode gegenüber der "Inspect" -Methode besteht darin, dass Sie das Modul nicht importieren müssen, damit es funktioniert, und Sie können eine Zeichenfolge für die Eingabe verwenden. Nützlich, wenn Sie beispielsweise Module überprüfen, die in einem anderen Skript aufgerufen wurden.

BEARBEITEN :

In Python3 importlib Modul tun:

Doc von importlib.util.find_spec :

Geben Sie die Spezifikation für das angegebene Modul zurück.

Zunächst wird sys.modules überprüft, ob das Modul bereits importiert wurde. Wenn ja, dann sys.modules [Name]. spez wird zurückgegeben. Wenn dies zufällig auf Keine gesetzt ist, wird ValueError ausgelöst. Befindet sich das Modul nicht in sys.modules, wird sys.meta_path nach einer geeigneten Spezifikation mit dem Wert 'path' durchsucht, der den Findern zugewiesen wurde. Keine wird zurückgegeben, wenn keine Spezifikation gefunden werden konnte.

Wenn der Name für das Submodul steht (einen Punkt enthält), wird das übergeordnete Modul automatisch importiert.

Die Argumente name und package funktionieren genauso wie importlib.import_module (). Mit anderen Worten, relative Modulnamen (mit führenden Punkten) funktionieren.


2
imp wird in Python 2 (aktuelle Version 2.7.13) NICHT abgeschrieben. imp wird in Python 3 seit 3.4 abgeschrieben. importlib soll stattdessen in Python 3 verwendet werden. Ich mag diese Lösung, weil sie sogar funktioniert, wenn der eigentliche Import fehlschlägt (z. B. weil 64-Bit-Modul für eine 32-Bit-Engine)
mdew

Und WIRKLICH schön, wenn versucht wird, den Pfad von 64-Bit-SQLite3 zu finden, und der Import fehlschlägt. Perfekt.
rahvin_t

2
importlib.machinery.PathFinder().find_module("os").get_filename()Die kürzeste Alternative zu imp.find_modulePython3 +. Wenn jemand nach der Verwendung von sucht importlib.util.find_spec.
Torxed

Diese Methode funktioniert ohne den Import des eigentlichen Moduls. Das ist großartig, da ich damit herausfinde, welche Version eines Moduls von einem gemeinsam genutzten Computer importiert wird.
Gouda

19

Das war trivial.

Jedes Modul hat eine __file__ Variable, die den relativen Pfad anzeigt, von dem aus Sie sich gerade befinden.

Daher ist es einfach, ein Verzeichnis für das Modul zu erhalten, um es zu benachrichtigen:

os.path.dirname(__file__)

14
Fast, aber nicht ganz richtig - die Datei ist nicht "relativ zu dem, wo Sie sich gerade befinden"; Wenn es relativ ist (was nur der Fall ist, wenn es in sys.path relative Pfade gibt), ist es relativ zu dem Ort, an dem Sie sich befanden, als das Modul geladen wurde .
Charles Duffy

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

1
funktioniert unter meinem Linux-Python 2.6 nicht, da __file__es sich nur um dir / test.py handelt. Abspath bezieht den cwd ein, um den Pfadnamen zu vervollständigen, der nicht das gewünschte Ergebnis ist. Wenn Sie jedoch ein Modul importieren, erhalten Sie m.__file__das gewünschte Ergebnis.
Ben Bryant

10
import module
print module.__path__

Pakete unterstützen ein weiteres spezielles Attribut __path__. Dies wird als Liste initialisiert, die den Namen des Verzeichnisses enthält, in dem sich das Paket befindet__init__.py bevor der Code in dieser Datei ausgeführt wird. Diese Variable kann geändert werden. Dies wirkt sich auf zukünftige Suchvorgänge nach Modulen und Unterpaketen aus, die im Paket enthalten sind.

Diese Funktion wird zwar nicht oft benötigt, kann jedoch zum Erweitern der in einem Paket enthaltenen Module verwendet werden.

Quelle


9

Befehlszeilenprogramm

Sie können es an einem Befehlszeilenprogramm anpassen.

python-which <package name>

Geben Sie hier die Bildbeschreibung ein


Erstellen /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__)

Mach es ausführbar

sudo chmod +x /usr/local/bin/python-which

7

Daher habe ich ziemlich viel Zeit damit verbracht, dies mit py2exe zu versuchen. Das Problem bestand darin, den Basisordner des Skripts abzurufen, unabhängig davon, ob es als Python-Skript oder als ausführbare py2exe-Datei ausgeführt wurde. Damit es funktioniert, ob es aus dem aktuellen Ordner, einem anderen Ordner oder (dies war der schwierigste) aus dem Systempfad ausgeführt wurde.

Schließlich habe ich diesen Ansatz verwendet und sys.frozen als Indikator für die Ausführung in py2exe verwendet:

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

Sie können Ihr Modul einfach importieren und dann auf seinen Namen klicken, um den vollständigen Pfad zu erhalten

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

4

Wenn Sie den Stammpfad des Pakets von einem seiner Module abrufen möchten, funktioniert Folgendes (getestet in Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

Der Hauptpfad __init__.pykann auch mit referenziert werden __file__.

Hoffe das hilft!


3

Wenn die einzige Einschränkung bei der Verwendung darin __file__besteht, dass das aktuelle relative Verzeichnis leer ist (dh wenn es als Skript aus demselben Verzeichnis ausgeführt wird, in dem sich das Skript befindet), lautet die einfache Lösung:

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

Und das Ergebnis:

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

Der Trick ist or '.'nach dem dirname()Anruf. Es setzt das Verzeichnis als ., was aktuelles Verzeichnis bedeutet und ein gültiges Verzeichnis für jede pfadbezogene Funktion ist.

Daher ist die Verwendung abspath()nicht wirklich erforderlich. Wenn Sie es trotzdem verwenden, wird der Trick nicht benötigt: abspath()Akzeptiert leere Pfade und interpretiert es ordnungsgemäß als aktuelles Verzeichnis.


Tauschen Sie die Reihenfolge besser aus und verwenden os.path.dirname(os.path.abspath(__file__))Sie sie einfach, da Sie sich dann überhaupt nicht um relative Pfade kümmern müssen. Eine Gelegenheit weniger für Fehler.
Szali

3

Ich möchte mit einem gemeinsamen Szenario (in Python 3) einen Beitrag leisten und einige Ansätze dafür untersuchen.

Die integrierte Funktion open () akzeptiert entweder den relativen oder den absoluten Pfad als erstes Argument. Der relative Pfad wird jedoch als relativ zum aktuellen Arbeitsverzeichnis behandelt. Es wird daher empfohlen, den absoluten Pfad an die Datei zu übergeben.

Wenn Sie eine Skriptdatei mit dem folgenden Code ausführen, kann nicht garantiert werden, dass die example.txtDatei in demselben Verzeichnis erstellt wird, in dem sich die Skriptdatei befindet:

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

Um diesen Code zu reparieren, müssen wir den Pfad zum Skript ermitteln und absolut machen. Um sicherzustellen, dass der Pfad absolut ist, verwenden wir einfach die Funktion os.path.realpath () . Um den Pfad zum Skript abzurufen, gibt es mehrere allgemeine Funktionen, die verschiedene Pfadergebnisse zurückgeben:

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

Beide Funktionen os.getcwd () und os.path.realpath () geben Pfadergebnisse basierend auf dem aktuellen Arbeitsverzeichnis zurück . Im Allgemeinen nicht das, was wir wollen. Das erste Element der Liste sys.argv ist der Pfad des Stammskripts (des von Ihnen ausgeführten Skripts), unabhängig davon, ob Sie die Liste im Stammskript selbst oder in einem seiner Module aufrufen. In einigen Situationen kann dies hilfreich sein. Die Variable __file__ enthält den Pfad des Moduls, von dem aus sie aufgerufen wurde.


Der folgende Code erstellt eine Datei korrekt example.txtin demselben Verzeichnis, in dem sich das Skript befindet:

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

with open(filepath, 'w'):
    pass

3

Wenn Sie den absoluten Pfad aus Ihrem Skript kennen möchten, können Sie das Path- Objekt verwenden:

from pathlib import Path

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

cwd () -Methode

Gibt ein neues Pfadobjekt zurück, das das aktuelle Verzeichnis darstellt (wie von os.getcwd () zurückgegeben).

Lösung () Methode

Machen Sie den Pfad absolut und lösen Sie alle Symlinks auf. Ein neues Pfadobjekt wird zurückgegeben:


1

Innerhalb der Module eines Python-Pakets musste ich auf eine Datei verweisen, die sich im selben Verzeichnis wie das Paket befand. 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

Also musste ich oben maincli.py aus dem Modul my_lib_a.py aufrufen, da ich wusste, dass sich top_package und maincli.py im selben Verzeichnis befinden. So erhalte ich den Pfad zu 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

Basierend auf der Veröffentlichung von PlasmaBinturong habe ich den Code geändert.


1

Wenn Sie dies dynamisch in einem "Programm" tun möchten, versuchen Sie diesen Code:
Mein Punkt ist, dass Sie möglicherweise nicht den genauen Namen des Moduls kennen, um es "fest zu codieren". Es kann aus einer Liste ausgewählt werden oder wird derzeit nicht ausgeführt, um __file__ zu verwenden.

(Ich weiß, es wird in Python 3 nicht funktionieren)

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'>

Ich habe versucht, das "globale" Problem zu beseitigen, aber Fälle gefunden, in denen es nicht funktioniert hat. Ich denke, "execfile ()" kann in Python 3 emuliert werden. Da dies in einem Programm enthalten ist, kann es leicht in eine Methode oder ein Modul für eingefügt werden Wiederverwendung.


0

Wenn Sie es mit pip installiert haben, funktioniert "pip show" hervorragend ('Location')

$ pip show detektron2

Name: detectron2
Version: 0.1
Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation.
Home-page: https://github.com/facebookresearch/detectron2
Author: FAIR
Author-email: None
License: UNKNOWN
Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages
Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore

0

Hier ist ein kurzes Bash-Skript für den Fall, dass es für irgendjemanden nützlich ist. Ich möchte nur in der Lage sein, eine Umgebungsvariable festzulegen, damit ich pushdauf den Code zugreifen kann .

#!/bin/bash
module=${1:?"I need a module name"}

python << EOI
import $module
import os
print os.path.dirname($module.__file__)
EOI

Shell-Beispiel:

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
[root@sri-4625-0004 ~]# echo $LXML
/usr/lib64/python2.7/site-packages/lxml
[root@sri-4625-0004 ~]#
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.