Python'da yürütülen geçerli dosyanın yolunu nasıl edinebilirim?


193

Bu acemi bir soru gibi görünebilir, ama değil. Bazı ortak yaklaşımlar her durumda işe yaramaz:

sys.argv [0]

Bu, kullanmak anlamına gelir path = os.path.abspath(os.path.dirname(sys.argv[0])), ancak başka bir dizindeki başka bir Python komut dosyasından çalıştırıyorsanız bu işe yaramaz ve bu gerçek hayatta olabilir.

__dosya__

Bu kullanmak anlamına gelir path = os.path.abspath(os.path.dirname(__file__)), ancak bunun işe yaramadığını gördüm:

  • py2exebir __file__niteliği yok, ancak bir geçici çözüm var
  • IDLE'den çalıştırdığınızda execute()hiçbir __file__özellik yok
  • OS X 10.6'yı nereden edinebilirim NameError: global name '__file__' is not defined

Eksik cevapları olan ilgili sorular:

Ben yukarıdaki tüm kullanım durumlarda işe yarayacak genel bir çözüm arıyorum .

Güncelleme

İşte bir test çantasının sonucu:

Python a.py çıktısı (Windows'ta)

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")

alt dizin / 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

ağaç

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

Yanıtlar:


80

Yürütülen ana komut dosyasının konumunu doğrudan belirleyemezsiniz. Sonuçta, bazen komut dosyası bir dosyadan gelmedi. Örneğin, etkileşimli yorumlayıcıdan veya yalnızca bellekte depolanan dinamik olarak oluşturulan koddan gelebilir.

Ancak, modüller her zaman bir dosyadan yüklendiğinden, bir modülün konumunu güvenilir bir şekilde belirleyebilirsiniz. Aşağıdaki kodla bir modül oluşturup ana komut dosyanızla aynı dizine koyarsanız, ana komut dosyası modülü içe aktarabilir ve bunu bulmak için kullanabilir.

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()

Farklı dizinlerde birkaç ana komut dosyanız varsa, module_locator'ın birden fazla kopyasına ihtiyacınız olabilir.

Elbette, ana komut dosyanız, komut dosyanızla birlikte bulunan modülleri içe aktarmanıza izin vermeyen başka bir araç tarafından yüklenirse, şansınız kalmaz. Bu gibi durumlarda, peşinde olduğunuz bilgiler programınızın hiçbir yerinde mevcut değildir. En iyi seçeneğiniz, aracın yazarlarına bir hata bildirmek olacaktır.


2
OS 10.6'da dosyayıNameError: global name '__file__' is not defined kullanıyorum ve bu IDLE içinde değil. Bunun yalnızca modüllerin içinde tanımlandığını düşünün . __file__
sorin

1
@Sorin Sbarnea: Cevabımı bununla nasıl başa çıktığım konusunda güncelledim.
Daniel Stutzbach

2
Teşekkürler, ama aslında eksik olan sorunun __file__Unicode ile ilgisi yoktu. Neden __file__tanımlanmadığını bilmiyorum ama bu her durumda işe yarayacak genel bir çözüm arıyorum.
sorin

1
Üzgünüz, bu her durumda mümkün değildir. Örneğin, bunu bir wscript dosyasının (python) içinden waf.googlecode.com'da yapmaya çalışıyorum. Bu dosyalar yürütülür, ancak modüller değildir ve modüller yapamazsınız (kaynak ağaçtan herhangi bir alt dizin olabilirler).
sorin

1
some_path/module_locator.pyBunun yerine size yerini vermeyecek mi ?
Casebash

68

İlk olarak, gelen ithalat gerekir inspectveos

from inspect import getsourcefile
from os.path import abspath

Sonra, kaynak dosyayı bulmak istediğiniz her yerde

abspath(getsourcefile(lambda:0))

En iyi cevap. Teşekkür ederim.
Devan Williams

4
Mükemmel cevap. Teşekkürler. Aynı zamanda en kısa ve en taşınabilir (farklı işletim sistemlerinde çalışıyor) yanıtı gibi görünüyor ve NameError: global name '__file__' is not defined(buna neden olan başka bir çözüm) gibi sorunlarla karşılaşmıyor .
Edward

Aynı şekilde kısa olan bir başka olasılık: lambda:_. Benim için çalıştı - her zaman işe yarayacağından emin değilim. lambda:0muhtemelen ölçülemeyecek kadar küçük bir miktar daha hızlı çalışır (veya belki de çok küçük değil ... bir yük anında veya 0küresel bir yük için daha da hızlı bir şey olabilir _mi?)
ArtOfWarfare

Denediğim hemen hemen her teklifte olduğu gibi, bu sadece benim için cwd döndürüyor, çalıştırdığım dizin dosyasını değil (hata ayıklama).
James

1
@James - Bu kod çalıştırdığınız dosyaya giriyor ... çalışıyor getsourcefile(lambda:0)anlamsız olacak ve sadece Noneetkileşimli bir istemde çalıştırmayı denerseniz geri dönecektir (çünkü lambdaherhangi bir kaynak dosyada olmayacaktır.) etkileşimli bir ortamda başka bir işlev veya nesnenin nereden geldiği, belki abspath(getsourcefile(thatFunctionOrObject))sizin için daha yararlı olacaktır?
ArtOfWarfare

16

bu çözüm yürütülebilir dosyalarda bile sağlamdır

import inspect, os.path

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

2
Bu doğru cevap olmalı. Bu bile çalışır entry_point: console_script, ancak diğer cevapların hiçbiri.
Polv

15

Benzer bir sorunla karşılaşıyordum ve bence bu sorunu çözebilir:

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

Düzenli komut dosyaları ve boşta çalışır. Söyleyebileceğim tek şey diğerleri için denemek!

Tipik kullanımım:

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

global __modpath__
__modpath__ = module_path(main)

Şimdi __file__ yerine __modpath__ kullanıyorum.


2
Göre PEP8 kodlama stil kılavuzu, bir çift kişilik öncü ve alt çizgi izleyen ile adları oluşturmak asla - yani __modpath__adlandırılması. Muhtemelen globalifadeye de ihtiyacınız yok . Aksi takdirde +1!
martineau

4
Aslında yerel işlevi doğrudan çağrıda tanımlayabilirsiniz module_path(). yani module_path(lambda _: None)içinde bulunduğu komut dosyasının diğer içeriğine bağlı değildir.
martineau

@martineau: lambda _: NoneNeredeyse son iki yıldır öneri aldım ve kullandım, ama şimdi sadece onu yoğunlaştırabildiğimi keşfettim lambda:0. Yaptığınız formu, _hiçbir argüman yerine yok sayılmış bir argümanla önermenizin belirli bir nedeni var mı ? NoneSadece boşluktan ziyade boşlukla ön eklenmiş üstün bir şey var mı 0? İkisi de eşit derecede şifreli, sanırım, biri 8 karakter uzunluğunda, diğeri 14 karakter uzunluğunda.
ArtOfWarfare

@ArtOfWarfare: İkisi arasındaki fark lambda _:, bir argüman alan ve lambda:hiç almayan bir fonksiyon olmasıdır . Önemli değil çünkü fonksiyon asla çağrılmaz. Benzer şekilde, hangi dönüş değerinin kullanıldığı önemli değildir. Sanırım seçtim Noneçünkü o zamanlar hiçbir şey yapmadı, hiçbir zaman çağrılmayacak bir işlev olduğunu daha iyi gösteriyor. Önündeki boşluk isteğe bağlıdır ve yine sadece daha iyi okunabilirlik için vardır (her zaman PEP8'i takip etmeye çalışmak alışkanlık oluşturur).
martineau

@martineau: Açıkçası lambdaolsa da, asla yapılması gerekmeyen bir şey için kullanmak bir kötüye kullanımdır . Eğer PEP8 izlendiğinde, bunun için doğru içerik olacağını düşünüyorum pass, değil None, ama bir bir açıklama koymak için geçerli değil lambdabir değerle şey koymak zorunda. Orada koyabilir birkaç geçerli 2 karakter şeyler, ama sen koyabilirsiniz tek geçerli tek karakter şeyler 0-9 olduğunu düşünüyorum (veya dışında atanmış tek bir karakter değişkeni adı lambda.) Düşündüm 0iyi 0- hiçliğini gösterir 9.
ArtOfWarfare

6

Kısa cevap, istediğiniz bilgiyi almanın garantili bir yolu olmadığı , ancak neredeyse her zaman pratikte çalışan buluşsal yöntemler var. Sen-ebilmek bulmak nasıl yürütülebilir dosya C bulmak? . Sorunu C açısından tartışıyor, ancak önerilen çözümler kolayca Python'a kopyalanıyor.


Merhaba, bayrağım reddedildi, bu yüzden şimdi meta hakkında bir tartışma başlattım: meta.stackoverflow.com/questions/277272/…
ArtOfWarfare

Bununla birlikte, bu sayfada zaten basit çalışma cevapları var. Çözümüm iyi çalışıyor: stackoverflow.com/a/33531619/3787376 .
Edward

5

Cevabımın neden güvenilir olmayan değişkeni kullanmadığı da dahil olmak üzere, ilgili bilgiler için Üst klasörden modül içe aktarma sorusuna verilen cevaba bakın __file__. Bu basit çözüm, modüller olarak farklı işletim sistemleriyle çapraz uyumlu olmalı osve inspectPython'un bir parçası olmalıdır.

İlk olarak, denetleme ve işletim sistemi modüllerinin parçalarını içe aktarmanız gerekir .

from inspect import getsourcefile
from os.path import abspath

Ardından, aşağıdaki satırı Python kodunuzda gerekli olan başka bir yerde kullanın:

abspath(getsourcefile(lambda:0))

Nasıl çalışır:

Yerleşik modülden os(aşağıdaki açıklama), abspatharaç alınır.

Hangi sistemde olduğumuza bağlı olarak Mac, NT veya Posix için işletim sistemi rutinleri.

Ardından getsourcefile(aşağıdaki açıklama) yerleşik modülden alınır inspect.

Canlı Python nesnelerinden yararlı bilgiler alın.

  • abspath(path) dosya yolunun mutlak / tam sürümünü döndürür
  • getsourcefile(lambda:0)bir şekilde lambda fonksiyon nesnesinin dahili kaynak dosyasını alır, bu nedenle '<pyshell#nn>'Python kabuğuna döner veya yürütülmekte olan Python kodunun dosya yolunu döndürür.

abspathSonuçta kullanıldığında , getsourcefile(lambda:0)oluşturulan dosya yolunun Python dosyasının tam dosya yolu olduğundan emin olun.
Açıklanan bu çözüm başlangıçta Python'da yürürlükte olan dosyanın yolunu nasıl alabilirim? .


evet ben aynı çözümü buldum ... güvenilir bir şekilde yapılamayacağını söyleyen cevaplardan çok daha iyi ... soru ne düşündüğümü sormadığı sürece ...
Grady Oyuncu

5

Basitçe aradınız:

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

onun yerine:

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

abspath()size mutlak yolunu sys.argv[0](kodunuzun bulunduğu dosya adı) verir ve dirname()dosya yolsuz dizin yolunu döndürür.


4

Bu, hileyi platformlar arası bir şekilde yapmalıdır (yorumlayıcı veya başka bir şey kullanmadığınız sürece):

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]arama komut dosyanızın bulunduğu dizindir (bu komut dosyası tarafından kullanılacak modülleri ilk aradığı yer). Dosyanın adını sonuna kadar alabiliriz sys.argv[0](bu benim yaptığım şeydir os.path.basename). os.path.joinsadece platformlar arası bir şekilde birbirine yapışır. os.path.realpathsadece betiğin gerçek ismini aldığımızdan betiğin kendisinden farklı adlara sahip herhangi bir sembolik bağlantı elde edersek emin olur.

Mac'im yok; bu yüzden bunu bir test etmedim. Lütfen işe yarayıp yaramadığını bize bildirin, olması gerektiği gibi. Bunu Python 3.4 ile Linux'ta (Xubuntu) test ettim. Bu sorun için birçok çözümün Mac'lerde çalışmadığını unutmayın (çünkü Mac'lerde __file__olmadığını duydum ).

Komut dosyanız sembolik bir bağlantıysa, bağlandığı dosyanın yolunu verecektir (sembolik bağın yolunu değil).


2

Sen kullanabilirsiniz Pathgelen pathlibmodül:

from pathlib import Path

# ...

Path(__file__)

parentYolda daha ileri gitmek için çağrıyı kullanabilirsiniz :

Path(__file__).parent

Bu yanıt, StackOverflow kullanıcılarının sıklıkla bahsettiği gibi, güvenilir__file__ olamayacak değişkeni kullanır (her zaman tam dosya yolu değildir, her işletim sisteminde çalışmaz vb.). Cevabın dahil edilmeyecek şekilde değiştirilmesi, daha az soruna neden olacak ve daha uyumlu olacaktır. Daha fazla bilgi için bkz. Stackoverflow.com/a/33532002/3787376 .
Edward

@ mrroot5 Tamam, yorumunuzu silin lütfen.
Gavriel Cohen

1

Kod bir dosyadan geliyorsa, tam adını alabilirsiniz

sys._getframe().f_code.co_filename

İşlev adını şu şekilde de alabilirsiniz: f_code.co_name


0

Aşağıdakileri eklemeniz yeterlidir:

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

Veya:

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

0

Benim çözümüm:

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

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

Bu mantıklı değil. Birincisi, '__file__'bir dize olmamalı, ikincisi, eğer yapmış olsaydınız __file__, bu sadece bu kod satırının bulunduğu dosya için çalışır, çalıştırılan dosya için değil mi?
Andreas Storvik Strauman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.