Hoe kom ik aan het pad van het huidige uitgevoerde bestand in Python?

Dit lijkt misschien een vraag voor beginners, maar dat is het niet. Sommige veelvoorkomende benaderingen werken niet in alle gevallen:

sys.argv[0]

Dit betekent dat u path = os.path.abspath(os.path.dirname(sys.argv[0]))gebruikt, maar dit werkt niet als u vanuit een ander Python-script in een andere directory, en dit kan in het echte leven ook gebeuren.

__file__

Dit betekent het gebruik van path = os.path.abspath(os.path.dirname(__file__)), maar ik ontdekte dat dit niet werkt:

  • py2exeheeft geen kenmerk __file__, maar er is een tijdelijke oplossing
  • Als je rent vanaf IDLEmet execute(), is er geen __file__kenmerk
  • Mac OS X v10.6(Snow Leopard) waar ik NameError: global name '__file__' is not defined

Verwante vragen met onvolledige antwoorden:

Ik ben op zoek naar een algemene oplossing, een die zou werken in alle bovenstaande gebruikssituaties.

Bijwerken

Hier is het resultaat van een testcase:

Uitvoer van python a.py(op Windows)

a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz
b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz

a.py

#! /usr/bin/env python
import os, sys
print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print
execfile("subdir/b.py")

Bestand subdir/b.py

#! /usr/bin/env python
import os, sys
print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print

boom

C:.
|   a.py
\---subdir
        b.py

Antwoord 1, autoriteit 100%

Je kunt niet direct de locatie bepalen van het hoofdscript dat wordt uitgevoerd. Soms kwam het script immers helemaal niet uit een bestand. Het kan bijvoorbeeld afkomstig zijn van de interactieve tolk of dynamisch gegenereerde code die alleen in het geheugen is opgeslagen.

U kunt echter betrouwbaar de locatie van een module bepalen, aangezien modules altijd vanuit een bestand worden geladen. Als je een module maakt met de volgende code en deze in dezelfde map plaatst als je hoofdscript, dan kan het hoofdscript de module importeren en die gebruiken om zichzelf te lokaliseren.

some_path/module_locator.py:

def we_are_frozen():
    # All of the modules are built-in to the interpreter, e.g., by py2exe
    return hasattr(sys, "frozen")
def module_path():
    encoding = sys.getfilesystemencoding()
    if we_are_frozen():
        return os.path.dirname(unicode(sys.executable, encoding))
    return os.path.dirname(unicode(__file__, encoding))

some_path/main.py:

import module_locator
my_path = module_locator.module_path()

Als je meerdere hoofdscripts in verschillende mappen hebt, heb je mogelijk meer dan één exemplaar van module_locator nodig.

Als je hoofdscript wordt geladen door een andere tool waarmee je geen modules kunt importeren die bij je script staan, heb je natuurlijk pech. In dat soort gevallen bestaat de informatie die u zoekt gewoonweg nergens in uw programma. Je kunt het beste een bug indienen bij de auteurs van de tool.


Antwoord 2, autoriteit 99%

Eerst moet u importeren vanuit inspecten os

from inspect import getsourcefile
from os.path import abspath

Vervolgens, waar je het bronbestand wilt vinden, gebruik je gewoon

abspath(getsourcefile(lambda:0))

Antwoord 3, autoriteit 28%

Deze oplossing is robuust, zelfs in uitvoerbare bestanden:

import inspect, os.path
filename = inspect.getframeinfo(inspect.currentframe()).filename
path     = os.path.dirname(os.path.abspath(filename))

Antwoord 4, autoriteit 18%

Ik liep tegen een soortgelijk probleem aan en ik denk dat dit het probleem zou kunnen oplossen:

def module_path(local_function):
   ''' returns the module path without the use of __file__.  Requires a function defined
   locally in the module.
   from http://stackoverflow.com/questions/729583/getting-file-path-of-imported-module'''
   return os.path.abspath(inspect.getsourcefile(local_function))

Het werkt voor reguliere scripts en in IDLE. Ik kan alleen maar zeggen: probeer het voor anderen!

Mijn typische gebruik:

from toolbox import module_path
def main():
   pass # Do stuff
global __modpath__
__modpath__ = module_path(main)

Nu gebruik ik _modpath_in plaats van _file_.


Antwoord 5, autoriteit 8%

U heeft zojuist gebeld:

path = os.path.abspath(os.path.dirname(sys.argv[0]))

in plaats van:

path = os.path.dirname(os.path.abspath(sys.argv[0]))

abspath()geeft je het absolute pad van sys.argv[0](de bestandsnaam waarin je code zich bevindt) en dirname()geeft het mappad terug zonder de bestandsnaam.


Antwoord 6, autoriteit 7%

Het korte antwoord is dat er geen gegarandeerde manier is om de gewenste informatie te krijgen, maar er zijn heuristieken die in de praktijk bijna altijd werken. Je zou kunnen kijken op Hoe vind ik de locatie van het uitvoerbare bestand in C?. Het bespreekt het probleem vanuit een C-oogpunt, maar de voorgestelde oplossingen kunnen eenvoudig worden getranscribeerd in Python.


Antwoord 7, autoriteit 7%

Zie mijn antwoord op de vraag Modules importeren uit bovenliggende mapvoor gerelateerde informatie, inclusief waarom mijn antwoord de onbetrouwbare variabele __file__niet gebruikt. Deze eenvoudige oplossing moet compatibel zijn met verschillende besturingssystemen, aangezien de modules osen inspectdeel uitmaken van Python.

Eerst moet u delen van de modules inspecten osimporteren.

from inspect import getsourcefile
from os.path import abspath

Gebruik vervolgens de volgende regel ergens anders in uw Python-code:

abspath(getsourcefile(lambda:0))

Hoe het werkt:

Vanuit de ingebouwde module os(beschrijving hieronder), wordt de tool abspathgeïmporteerd.

OS-routines voor Mac, NT of Posix, afhankelijk van het systeem waarop we werken.

Vervolgens wordt getsourcefile(beschrijving hieronder) geïmporteerd vanuit de ingebouwde module inspect.

Verkrijg nuttige informatie van live Python-objecten.

  • abspath(path)retourneert de absolute/volledige versie van een bestandspad
  • getsourcefile(lambda:0)haalt op de een of andere manier het interne bronbestand van het lambda-functieobject op, dus retourneert '<pyshell#nn>'in de Python-shell of geeft het bestandspad terug van de Python-code die momenteel wordt uitgevoerd.

Het gebruik van abspathop het resultaat van getsourcefile(lambda:0)moet ervoor zorgen dat het gegenereerde bestandspad het volledige bestandspad van het Python-bestand is.
Deze uitgelegde oplossing was oorspronkelijk gebaseerd op code uit het antwoord op Hoe kom ik aan het pad van het huidige uitgevoerde bestand in Python?.


Antwoord 8, autoriteit 6%

Dit zou de truc op een platformonafhankelijke manier moeten doen (zolang je de tolk of iets dergelijks niet gebruikt):

import os, sys
non_symbolic=os.path.realpath(sys.argv[0])
program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic))

sys.path[0]is de directory waarin je aanroepende script zich bevindt (de eerste plaats waar het zoekt naar modules die door dat script moeten worden gebruikt). We kunnen de naam van het bestand zelf van het einde van sys.argv[0]halen (wat ik deed met os.path.basename). os.path.joinplakt ze gewoon op een platformonafhankelijke manier bij elkaar. os.path.realpathzorgt er alleen voor dat als we symbolische links krijgen met andere namen dan het script zelf, we nog steeds de echte naam van het script krijgen.

Ik heb geen Mac; dus ik heb dit niet getest op een. Laat het me weten als het werkt, zoals het lijkt te moeten. Ik heb dit getest in Linux (Xubuntu) met Python 3.4. Merk op dat veel oplossingen voor dit probleem niet werken op Macs (omdat ik heb gehoord dat __file__niet aanwezig is op Macs).

Houd er rekening mee dat als uw script een symbolische link is, het u het pad geeft van het bestand waarnaar het linkt (en niet het pad van de symbolische link).


Antwoord 9, autoriteit 5%

U kunt Pathgebruiken uit de module pathlib:

from pathlib import Path
# ...
Path(__file__)

U kunt de oproep naar parentgebruiken om verder te gaan in het pad:

Path(__file__).parent

Antwoord 10

Voeg eenvoudig het volgende toe:

from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)

Of:

from sys import *
print(sys.argv[0])

Antwoord 11

Als de code uit een bestand komt, kun je de volledige naam krijgen

sys._getframe().f_code.co_filename

U kunt de functienaam ook ophalen als f_code.co_name


Antwoord 12

Het belangrijkste idee is dat iemand je python-code zal uitvoeren, maar je moet de map hebben die het dichtst bij het python-bestand ligt.

Mijn oplossing is:

import os
print(os.path.dirname(os.path.abspath(__file__)))

Met
os.path.dirname(os.path.abspath(__file__))
U kunt het gebruiken om foto’s, uitvoerbestanden, … enz. op te slaan


Antwoord 13

import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

Other episodes