Domanda

Voglio rilevare se il modulo è cambiato. Ora, usare inotify è semplice, devi solo conoscere la directory da cui vuoi ricevere le notifiche.

Come posso recuperare il percorso di un modulo in Python?

È stato utile?

Soluzione

import a_module
print(a_module.__file__)

Ti fornirà effettivamente il percorso del file .pyc che è stato caricato, almeno su Mac OS X. Quindi immagino che tu possa fare:

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

Puoi anche provare:

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

Per ottenere la directory del modulo.

Altri suggerimenti

Esiste il modulo inspect in Python.

Documentazione ufficiale

  

Il modulo inspect offre diverse utili funzioni per ottenere   informazioni su oggetti live come moduli, classi, metodi,   funzioni, traceback, oggetti frame e oggetti code. Per esempio,   può aiutarti a esaminare il contenuto di una classe, recuperare la fonte   codice di un metodo, estrarre e formattare l'elenco degli argomenti per una funzione,   oppure ottieni tutte le informazioni necessarie per visualizzare un traceback dettagliato.

Esempio:

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

Come hanno detto le altre risposte, il modo migliore per farlo è con __file__ (di nuovo dimostrato di seguito). Tuttavia, esiste un avvertimento importante, ovvero che __file__ NON esiste se si esegue il modulo da solo (ovvero come __main__ ).

Ad esempio, supponi di avere due file (entrambi presenti sul tuo PYTHONPATH):

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

e

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

L'esecuzione di foo.py darà l'output:

/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

TUTTAVIA se provi a eseguire bar.py da solo, otterrai:

/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 

Spero che questo aiuti. Questo avvertimento mi è costato molto tempo e confusione durante il test delle altre soluzioni presentate.

Proverò ad affrontare alcune variazioni anche su questa domanda:

  1. trova il percorso dello script chiamato
  2. trova il percorso dello script attualmente in esecuzione
  3. trova la directory dello script chiamato

(Alcune di queste domande sono state poste su SO, ma sono state chiuse come duplicate e reindirizzate qui.)

Avvertenze sull'uso di __file__

Per un modulo che hai importato:

import something
something.__file__ 

restituirà il assoluto percorso del modulo. Tuttavia, dato lo script folowing foo.py:

#foo.py
print '__file__', __file__

Chiamandolo con 'python foo.py' Restituirà semplicemente 'foo.py'. Se aggiungi un shebang:

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

e chiamalo usando ./foo.py, restituirà './foo.py'. Chiamandolo da una directory diversa, (ad esempio metti foo.py nella barra delle directory), quindi chiamando

python bar/foo.py

o aggiungendo uno shebang ed eseguendo direttamente il file:

bar/foo.py

restituirà 'bar / foo.py' (il percorso relativo).

Ricerca della directory

Ora andando da lì per ottenere la directory, os.path.dirname (__ file__) può anche essere complicato. Almeno sul mio sistema, restituisce una stringa vuota se la chiami dalla stessa directory del file. es.

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

produrrà:

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

In altre parole, restituisce una stringa vuota, quindi questo non sembra affidabile se si desidera utilizzarlo per l'attuale file (al contrario del file di un modulo importato). Per aggirare questo, puoi avvolgerlo in una chiamata a 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__))

che genera qualcosa come:

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

Nota che abspath () NON risolve i collegamenti simbolici. Se vuoi farlo, usa invece realpath (). Ad esempio, creare un link simbolico file_import_testing_link che punta a file_import_testing.py, con il seguente contenuto:

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

l'esecuzione stamperà percorsi assoluti come:

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

file_import_testing_link - > file_import_testing.py

Uso di inspect

@SummerBreeze menziona l'uso del modulo inspect .

Questo sembra funzionare bene, ed è abbastanza conciso, per i moduli importati:

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

restituisce obbedientemente il percorso assoluto. Tuttavia, per trovare il percorso dello script attualmente in esecuzione, non ho visto un modo per usarlo.

Non capisco perché nessuno ne parli, ma per me la soluzione più semplice sta usando imp.find_module (" modulename ") (documentazione here ):

import imp
imp.find_module("os")

Dà una tupla con il percorso in seconda posizione:

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

Il vantaggio di questo metodo rispetto a "ispeziona" uno è che non è necessario importare il modulo per farlo funzionare ed è possibile utilizzare una stringa in input. Utile quando si controllano moduli chiamati ad esempio in un altro script.

Modifica :

In python3, il modulo importlib dovrebbe fare:

Doc di importlib.util.find_spec :

  

Restituisce le specifiche per il modulo specificato.

     

Innanzitutto, sys.modules viene controllato per vedere se il modulo è già stato importato. In tal caso, viene restituito sys.modules [nome]. specifica . Se succede   impostato su Nessuno, quindi viene generato ValueError. Se il modulo non è presente   sys.modules, quindi sys.meta_path viene cercata una specifica adatta con   valore del 'percorso' dato ai cercatori. Nessuno viene restituito se nessuna specifica poteva   essere trovato.

     

Se il nome è per sottomodulo (contiene un punto), lo è il modulo genitore   importato automaticamente.

     

Il nome e gli argomenti del pacchetto funzionano allo stesso modo di importlib.import_module ().   In altre parole, i nomi dei moduli relativi (con punti iniziali) funzionano.

Questo è stato banale.

Ogni modulo ha una variabile __file__ che mostra il suo percorso relativo da dove ti trovi adesso.

Pertanto, ottenere una directory per la notifica al modulo è semplice come:

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

Utilità da riga di comando

Puoi modificarlo in un'utilità della riga di comando,

python-which <package name>

 inserisci qui la descrizione dell'immagine


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

Rendi eseguibile

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

Quindi ho trascorso un bel po 'di tempo cercando di farlo con py2exe Il problema era ottenere la cartella di base dello script se veniva eseguito come script Python o come eseguibile py2exe. Inoltre, per farlo funzionare indipendentemente dal fatto che fosse eseguito dalla cartella corrente, da un'altra cartella o (questa era la più difficile) dal percorso del sistema.

Alla fine ho usato questo approccio, usando sys.frozen come indicatore di esecuzione in 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__))
import module
print module.__path__
  

I pacchetti supportano un altro attributo speciale, __path__ . Questo è   inizializzato per essere un elenco contenente il nome della directory holding   il __init__.py del pacchetto prima dell'esecuzione del codice in quel file.   Questa variabile può essere modificata; ciò influisce sulle ricerche future per   moduli e pacchetti secondari contenuti nel pacchetto.

     

Sebbene questa funzione non sia spesso necessaria, può essere utilizzata per estendere il   insieme di moduli trovati in un pacchetto.

Source

puoi semplicemente importare il tuo modulo quindi premi il suo nome e otterrai il suo percorso completo

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

Se l'unico avvertimento dell'uso di __file__ è quando corrente, la relativa directory è vuota (cioè, quando viene eseguita come uno script dalla stessa directory in cui si trova lo script), allora una soluzione banale è:

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

E il risultato:

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

Il trucco è in o '.' dopo la chiamata dirname () . Imposta dir come . , che significa directory corrente ed è una directory valida per qualsiasi funzione relativa al percorso.

Pertanto, l'uso di abspath () non è veramente necessario. Ma se lo usi comunque, il trucco non è necessario: abspath () accetta i percorsi vuoti e lo interpreta correttamente come la directory corrente.

Vorrei contribuire con uno scenario comune (in Python 3) ed esplorare alcuni approcci ad esso.

La funzione integrata open () accetta entrambi i relativi o percorso assoluto come primo argomento. Il percorso relativo viene trattato come relativo alla directory di lavoro corrente , sebbene sia consigliabile passare il percorso assoluto al file.

Detto semplicemente, se si esegue un file di script con il seguente codice, non è garantito che il file example.txt verrà creato nella stessa directory in cui il file di script si trova:

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

Per correggere questo codice dobbiamo ottenere il percorso dello script e renderlo assoluto. Per garantire che il percorso sia assoluto, utilizziamo semplicemente il os .path.realpath () . Per ottenere il percorso dello script ci sono diverse funzioni comuni che restituiscono vari risultati del percorso:

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

Entrambe le funzioni os.getcwd () e < a href = "https://docs.python.org/3/library/os.path.html#os.path.realpath" rel = "nofollow noreferrer"> os.path.realpath () percorso di ritorno risultati basati sulla directory di lavoro corrente . Generalmente non quello che vogliamo. Il primo elemento dell'elenco sys.argv è < em> percorso dello script di root (lo script che esegui) indipendentemente dal fatto che tu chiami l'elenco nello script di root stesso o in uno dei suoi moduli. Potrebbe tornare utile in alcune situazioni. La variabile __file__ contiene il percorso del modulo da cui è stato chiamato .


Il codice seguente crea correttamente un file example.txt nella stessa directory in cui si trova lo script:

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

with open(filepath, 'w'):
    pass

Dall'interno dei moduli di un pacchetto Python ho dovuto fare riferimento a un file che risiedeva nella stessa directory del pacchetto. Es.

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

Quindi in precedenza ho dovuto chiamare maincli.py dal modulo my_lib_a.py sapendo che top_package e maincli.py sono nella stessa directory. Ecco come ottengo il percorso per 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

Sulla base della pubblicazione di PlasmaBinturong ho modificato il codice.

Se desideri farlo in modo dinamico in un "programma" prova questo codice:
Il mio punto è che potresti non conoscere il nome esatto del modulo per "hardcode" esso. Potrebbe essere selezionato da un elenco o potrebbe non essere attualmente in esecuzione per utilizzare __file__.

(Lo so, non funzionerà in 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'>

Ho provato a sbarazzarmi del " global " problema ma trovato casi in cui non ha funzionato Penso che " execfile () " può essere emulato in Python 3 Poiché questo è in un programma, può essere facilmente inserito in un metodo o modulo per il riutilizzo.

Se desideri conoscere il percorso assoluto del tuo script, puoi utilizzare Path object:

from pathlib import Path

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

metodo cwd ()

  

Restituisce un nuovo oggetto path che rappresenta la directory corrente (come restituito da os.getcwd ())

metodo resol ()

  

Rendi assoluto il percorso, risolvendo eventuali collegamenti simbolici. Viene restituito un nuovo oggetto path:

Se vuoi recuperare il percorso root del pacchetto da uno qualsiasi dei suoi moduli, il seguente funziona (testato su Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

Il percorso principale __init__.py può anche essere referenziato usando invece __file__ .

Spero che questo aiuti!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top