Yürütülmekte olan dosyanın yolunu ve adını nasıl edinebilirim?


482

Diğer komut dosyalarını çağıran komut dosyaları var ama şu anda işlem içinde çalışan dosyanın dosya yolunu almak gerekir.

Diyelim ki üç dosyam var. Execfile kullanma :

  • script_1.pyçağrıları script_2.py.
  • Buna karşılık, script_2.pyaramalar script_3.py.

Nasıl dosya adını ve yolunu alabilirsiniz script_3.py, içinde koddanscript_3.py gelen argümanlar olarak bu bilgileri geçmek zorunda kalmadan, script_2.py?

(Yürütme os.getcwd(), geçerli başlangıç ​​komut dosyasının dosya yolunu geçerli dosyanın değil döndürür.)



2
os.path.realpath ( dosya )
Girish Gupta

Yanıtlar:


256

p1.py:

execfile("p2.py")

p2.py:

import inspect, os
print (inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print (os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) # script directory

11
DİKKAT: Bu çağrı farklı ortamlarda aynı sonucu vermez. Aşağıdaki Usagi'nin cevabını kabul etmeyi düşünün: stackoverflow.com/a/6628348/851398
faraday

3
@faraday: Bir örnek verebilir misiniz? Benzer soruyu kullanarakinspect.getabsfile() cevapladım ve denediğim tüm vakalar için çalıştı.
jfs

1
Gerçekten @Usagi yanıtı daha mı iyi?
Dror

4
nah user13993 çok daha iyi çivilenmiş
osirisgothra

6
user13993 gerçekten çivilenmiştir. Olmalıos.path.realpath(__file__)
uchuugaka

566
__file__

diğerleri söylediler. Sembolik bağlantıları ortadan kaldırmak için os.path.realpath komutunu da kullanmak isteyebilirsiniz :

import os

os.path.realpath(__file__)

14
Bu yaklaşıma dikkat etmek gerekir, çünkü bazen __file__'script_name.py' ve diğer zamanlarda 'script_name.pyc' döndürür. Yani çıktı sabit değil.
mekhatroner

27
Ancak bu dosyanın yolunu yalnızca alakasız kullandığımız için.
Uwe Koloska

5
bu garip: "__file__"tırnak içinde komut satırından (dize olarak) çalıştırıldığında cmd'nin çalıştırıldığı dizini verir, ancak __file__ (tırnak işaretleri olmadan kaynak dosyanın yolunu verir ... neden
muon

7
@muon, bir dosya adı dizesinin geçip geçmediğine dair bir denetim yapılmaz ve dosya yolları cwd'ye göreli olduğundan, os.path.realpathişlev diryolun bir parçası olduğunu varsayar . os.path.dirname(os.path.realpath(__file__))dosyayı içeren dizini döndürür. os.path.dirname(os.path.realpath("__file__"))cwd döndürür. os.path.dirname(os.path.realpath("here_be_dragons"))ayrıca cwd döndürür.
Jamie Bull

86

Güncelleme 2018-11-28:

İşte Python 2 ve 3 ile yapılan deneylerin bir özeti.


main.py - foo.py çalıştırır foo.py - lib / bar.py çalıştırır
lib / bar.py - dosyayolu ifadelerini yazdırır

| Python | Run statement       | Filepath expression                    |
|--------+---------------------+----------------------------------------|
|      2 | execfile            | os.path.abspath(inspect.stack()[0][1]) |
|      2 | from lib import bar | __file__                               |
|      3 | exec                | (wasn't able to obtain it)             |
|      3 | import lib.bar      | __file__                               |

Python 2 için, paketlere geçmek daha açık olabilir, bu yüzden kullanabilirsiniz from lib import bar- sadece __init__.pyiki klasöre boş dosyalar ekleyin .

Python 3 için, execfilemevcut değil - en yakın alternatif exec(open(<filename>).read()), ancak yığın çerçevelerini etkiler. Sadece kullanımı en basit import foove import lib.bar- __init__.pydosya gerekmez.

Ayrıca bkz. İçe aktarma ve execfile arasındaki fark


Orijinal cevap:

İşte Windows'taki Python 2.7.10 ile bu konudaki cevaplara dayanan bir deney.

Yığın tabanlı olanlar, güvenilir sonuçlar veren tek kişilerdir. Son ikisi en kısa sözdizimine sahiptir , yani -

print os.path.abspath(inspect.stack()[0][1])                   # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib

İşte bunlara fonksiyon olarak sys'e ekleniyor ! @Usagi ve @pablog'a teşekkür ederiz

Aşağıdaki üç dosyaya dayanarak ve python main.pymain.py ile klasöründen çalıştırılır (ayrıca mutlak yollarla yürütme ve ayrı bir klasörden çağırma).

C: \ execfile('foo.py')
dosyayolları \ main.py: execfile('lib/bar.py')
C: \ dosyayolları \ foo.py: C: \ dosyayolları \ lib \ bar.py:

import sys
import os
import inspect

print "Python " + sys.version
print

print __file__                                        # main.py
print sys.argv[0]                                     # main.py
print inspect.stack()[0][1]                           # lib/bar.py
print sys.path[0]                                     # C:\filepaths
print

print os.path.realpath(__file__)                      # C:\filepaths\main.py
print os.path.abspath(__file__)                       # C:\filepaths\main.py
print os.path.basename(__file__)                      # main.py
print os.path.basename(os.path.realpath(sys.argv[0])) # main.py
print

print sys.path[0]                                     # C:\filepaths
print os.path.abspath(os.path.split(sys.argv[0])[0])  # C:\filepaths
print os.path.dirname(os.path.abspath(__file__))      # C:\filepaths
print os.path.dirname(os.path.realpath(sys.argv[0]))  # C:\filepaths
print os.path.dirname(__file__)                       # (empty string)
print

print inspect.getfile(inspect.currentframe())         # lib/bar.py

print os.path.abspath(inspect.getfile(inspect.currentframe())) # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # C:\filepaths\lib
print

print os.path.abspath(inspect.stack()[0][1])          # C:\filepaths\lib\bar.py
print os.path.dirname(os.path.abspath(inspect.stack()[0][1]))  # C:\filepaths\lib
print

72

Bunun daha temiz olduğunu düşünüyorum:

import inspect
print inspect.stack()[0][1]

ve şu bilgileri alır:

print inspect.getfile(inspect.currentframe())

[0] yığındaki (yığının üst kısmı) geçerli kare ve [1] dosya adı içinse, artışın yığının içinde geriye doğru gitmesi yani

print inspect.stack()[1][1]

geçerli kareyi çağıran komut dosyasının dosya adı olur. Ayrıca, [-1] kullanıldığında, orijinal çağrı komut dosyası olan yığının en altına gidersiniz.


4
Tüpün içindeki pozisyona güvenmenizi önermeyin. Kodu okurken hangi verileri almaya çalıştığınız açık değildir.
19:18 '

5
inspect.getfile()__file__bir modül nesnesi geçtiyse özniteliği döndürür . inspect.currentframe()modülü döndürür. Ergo, bu pahalı bir yol __file__.
Martijn Pieters

inspect.stack()oldukça pahalı bir fonksiyon, sadece daha fazlası inspect.currentframe()ve inspect.getfile()bir modül nesnesini de çağırıyor .
Martijn Pieters

42
import os
os.path.dirname(__file__) # relative directory path
os.path.abspath(__file__) # absolute file path
os.path.basename(__file__) # the file name only

1
Az önce @Pat Notz'un yorumunu denedim. Bence sadece dosya ismini alabilirsin __file__.
hlin117

Python3'te, os.path.dirnamekomut dosyasını çalıştırdığınız göreli yolu size verecektir. mesela betiğin mutlak yolu değil python ../../test.py, os.path.dirnameolacaktır ../../. Abspath arıyordum ama senaryonun adını kaldırıyordum. Görünüşe göre sys.path'in ilk öğesi yanıttır sys.path[0].
aerijman

37

Komut dosyanız yalnızca bir dosyadan oluşuyorsa, en iyi olarak işaretlenen önerilerin tümü doğrudur.

Modül olarak içe aktarılabilecek bir dosyadan yürütülebilir dosyanın adını (yani, geçerli program için python yorumlayıcısına iletilen kök dosyayı) bulmak istiyorsanız, bunu yapmanız gerekir (bunun bir dosyada olduğunu varsayalım foo.py ) olarak adlandırılır :

import inspect

print inspect.stack()[-1][1]

Çünkü son şey ([-1] yığındaki ) içine giren ilk şeydir (yığınlar LIFO / FILO veri yapılarıdır).

Sonra dosya içinde bar.py eğer import fooo basalım bar.py ziyade, foo.py bunların hepsi değeri olur ki,:

  • __file__
  • inspect.getfile(inspect.currentframe())
  • inspect.stack()[0][1]

İyi çalışıyor ama tutulma üzerinde birim testi için değil, /home/user/Softwares/eclipse/plugins/org.python.pydev_4.5.5.201603221110/pysrc
hayj

2
Bu sys.modules['__main__'].__file__gerçekten yazımın pahalı bir yoludur .
Martijn Pieters

14
import os
print os.path.basename(__file__)

bu bize sadece dosya adını verecektir. yani dosya abspath'ı c: \ abcd \ abc.py ise 2. satır abc.py yazdıracaktır


14

"İşlem içinde çalışmakta olan dosyanın dosya yolu" ile ne demek istediğinizi tam olarak açık değil. sys.argv[0]genellikle komut dosyasının Python yorumlayıcısı tarafından çağrılan konumunu içerir. Kontrol sys belgeleri daha fazla ayrıntı için.

@Tim ve @Pat Notz'ın işaret ettiği gibi, __file__ özelliği

bir dosyadan yüklendiyse, modülün yüklendiği dosya


1
Python programını bir win32 exe'ye geçirdiğimizde "print os.path.abspath ( dosya )" ve "print inspect.getfile (inspect.currentframe ())" çalışmaz. Sadece sys.argv [0] çalışıyor! :) ama sadece adını alırsın!
aF.

11

Windows ortamında çalışması gereken bir komut dosyası var. Bu kod snipped ile bitirdim olduğunu:

import os,sys
PROJECT_PATH = os.path.abspath(os.path.split(sys.argv[0])[0])

bu oldukça kötü bir karardır. Ancak harici kütüphaneler gerektirmez ve benim durumumdaki en önemli şeydir.


1
Bunun için "os, sys" almak zorunda kaldı, ama şimdiye kadar aslında dizenin sonunda bir dosya adı olmadan sadece yolu döndüren en iyi cevap.
emmagras

10

Bunu dene,

import os
os.path.dirname(os.path.realpath(__file__))

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

İncelemeye veya başka bir kütüphaneye gerek yok.

İçe aktarılan komut dosyasıyla aynı klasörde bulunan bir yapılandırma dosyasını kullanan bir komut dosyasını (farklı bir dizinden sonra çalıştırılan komut dosyasını) almak zorunda kaldığımda bu benim için çalıştı.


Geçerli çalışma dizini (os.getcwd) dosyanın bulunduğu dizinden farklıysa, istenen yanıt üretilmez.
Demir Yastık

2
Nasıl yani? Bu durumda benim için iyi çalışıyor. Dosyanın bulunduğu dizini alıyorum.
Michael Mior

@IronPillow belki bu cevap ihtiyacınız olan şey konusunda size yardımcı olacaktır. stackoverflow.com/a/41546830/3123191
Kwuite


6
import sys

print sys.path[0]

bu, yürütülmekte olan komut dosyasının yolunu yazdıracaktır


2
sys.path [0] çok yararlıdır, ancak script1'in yolunu verir, script3 istendiği gibi değil
James

En azından OS X'te, 2.7 ile, bunun güvenilir bir şey yaptığını bulamıyorum. Doğrudan aynı dosya yürütülürse çalışır.
Repl


4

Kullanabilirsiniz inspect.stack()

import inspect,os
inspect.stack()[0]  => (<frame object at 0x00AC2AC0>, 'g:\\Python\\Test\\_GetCurrentProgram.py', 15, '<module>', ['print inspect.stack()[0]\n'], 0)
os.path.abspath (inspect.stack()[0][1]) => 'g:\\Python\\Test\\_GetCurrentProgram.py'

4

Python 3 oldukça yaygın olduğundan pathlib, muhtemelen dosya ve yol bilgilerine erişmek için daha iyi bir araç olduğuna inandığım için bir cevap eklemek istedim .

from pathlib import Path

current_file: Path = Path(__file__).resolve()

Geçerli dosyanın dizinini arıyorsanız .parent, Path()ifadeye eklemek kadar kolaydır :

current_path: Path = Path(__file__).parent.resolve()

3
import sys
print sys.argv[0]

10
Ne yazık ki bu sadece komut dosyasının tam yolu ile çağrıldıysa çalışır, çünkü komut dosyasına çağrı yapan komut satırında yalnızca "ilk bağımsız değişkeni" döndürür.
cregox

2

Bu çalışmalı:

import os,sys
filename=os.path.basename(os.path.realpath(sys.argv[0]))
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))

2
print(__file__)
print(__import__("pathlib").Path(__file__).parent)

4
Yalnızca kod yanıtları önerilmez. Lütfen bunun sorunu nasıl çözdüğüne veya mevcut cevaplardan nasıl farklı olduğuna dair biraz açıklama ekleyin. Şu kaynaktan
Nick

1

Yürütülen komut dosyasının dizinini almak için

 print os.path.dirname( inspect.getfile(inspect.currentframe()))

1

Her zaman Geçerli Çalışma Dizini veya CWD'nin os özelliğini kullandım. Bu standart kütüphanenin bir parçasıdır ve uygulanması çok kolaydır. İşte bir örnek:

    import os
    base_directory = os.getcwd()

1
Yanıtınızı, sorulan soruya uygulanacak şekilde değiştirebilir misiniz? Bu yanıt "
Marco

1
Bu, python komutunu çalıştırdığınız yerden yol verir. Bu nedenle, python script.pykomutu zaten bulunduğunuz klasörde çalıştırdığınızda pwd, gerçekte linux üzerinde çalışanla aynı olduğunda çalışır gibi görünüyor .
George

0

Ben __file__ ile yaklaşımı kullandım
os.path.abspath(__file__)
ama küçük bir hile var, kod ilk kez çalıştırıldığında .py dosyasını döndürür, sonraki çalışır * .pyc dosyasının adını verir,
böylece kaldım:
inspect.getfile(inspect.currentframe())
veya
sys._getframe().f_code.co_filename


0

Eclipse debugger ve unittest'i dikkate alan bir fonksiyon yazdım . Başlattığınız ilk komut dosyasının klasörünü döndürür. İsteğe bağlı olarak __file__ var öğesini belirtebilirsiniz , ancak asıl önemli olan, bu değişkeni tüm arama hiyerarşinizde paylaşmanız gerekmemesidir. .

Belki başkalarını göremediğim özel durumlarla başa çıkabilirsin, ama benim için sorun değil.

import inspect, os
def getRootDirectory(_file_=None):
    """
    Get the directory of the root execution file
    Can help: http://stackoverflow.com/questions/50499/how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executing
    For eclipse user with unittest or debugger, the function search for the correct folder in the stack
    You can pass __file__ (with 4 underscores) if you want the caller directory
    """
    # If we don't have the __file__ :
    if _file_ is None:
        # We get the last :
        rootFile = inspect.stack()[-1][1]
        folder = os.path.abspath(rootFile)
        # If we use unittest :
        if ("/pysrc" in folder) & ("org.python.pydev" in folder):
            previous = None
            # We search from left to right the case.py :
            for el in inspect.stack():
                currentFile = os.path.abspath(el[1])
                if ("unittest/case.py" in currentFile) | ("org.python.pydev" in currentFile):
                    break
                previous = currentFile
            folder = previous
        # We return the folder :
        return os.path.dirname(folder)
    else:
        # We return the folder according to specified __file__ :
        return os.path.dirname(os.path.realpath(_file_))

0

Platformlarda (macOS / Windows / Linux) geçiş tutarlılığını korumak için şunları deneyin:

path = r'%s' % os.getcwd().replace('\\','/')


2
Bu yanlış. Bu size geçerli yolu alır, ancak geçerli dosyanın yolunu almaz.
Charles Plager

0

En basit yol:

içinde script_1.py:

import subprocess
subprocess.call(['python3',<path_to_script_2.py>])

içinde script_2.py:

sys.argv[0]

PS: Denedim execfile, ancak script_2.py bir dize olarak okuduğundan beri sys.argv[0]geri döndü <string>.


0

İşte kullandığım kodumu herhangi bir yere sorunsuz bir şekilde atabilirim. __name__her zaman tanımlanır, ancak __file__yalnızca kod bir dosya olarak çalıştırıldığında tanımlanır (örneğin, IDLE / iPython'da değil).

    if '__file__' in globals():
        self_name = globals()['__file__']
    elif '__file__' in locals():
        self_name = locals()['__file__']
    else:
        self_name = __name__

Alternatif olarak, bu şu şekilde yazılabilir:

self_name = globals().get('__file__', locals().get('__file__', __name__))

-2

Bu yanıtların çoğu Python sürüm 2.x veya önceki sürümlerinde yazılmıştır. Python 3.x'de yazdırma işlevinin sözdizimi parantez gerektirecek şekilde değiştirildi, yani print ().

Yani, Python 2.x'teki user13993'ten bu daha yüksek puan

import inspect, os
print inspect.getfile(inspect.currentframe()) # script filename (usually with path)
print os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory

Python 3.x'te olur:

import inspect, os
print(inspect.getfile(inspect.currentframe())) # script filename (usually with path)
print(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) ) # script directory

-3

sadece dosya adını olmadan istiyorsanız ./veya .pybunu deneyebilirsiniz

filename = testscript.py
file_name = __file__[2:-3]

file_name [] içindeki dizini değiştirerek istediğinizi oluşturabileceğiniz testscript yazdıracaktır


-3
import os

import wx


# return the full path of this file
print(os.getcwd())

icon = wx.Icon(os.getcwd() + '/img/image.png', wx.BITMAP_TYPE_PNG, 16, 16)

# put the icon on the frame
self.SetIcon(icon)

7
os.getcwd () şu anda yürütülen dosyanın dizinini değil, PROCESS öğesinin geçerli ÇALIŞMA dizinini döndürür. Bu, doğru sonuçları döndürüyor gibi görünebilir, ancak sonucun geçerli dosyanın üst dizini olmayacağı birçok durum vardır. Yukarıda önerildiği gibi os.path.dirname ( dosya ) kullanmak çok daha iyi .
samaspin
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.