Python'daki göreli yollar


245

Geçerli dizine kod tabanımızdaki birkaç şablon dosyasını kopyalayacak olan iş için basit bir yardımcı komut dosyası oluşturuyorum. Ancak, şablonların depolandığı dizine mutlak bir yol yok. Komut dosyasından göreli bir yol var ama komut dosyasını çağırdığınızda, geçerli çalışma dizinine göre bir yol olarak davranır. Bu göreli URL'nin komut dosyasının konumundan olduğunu belirtmenin bir yolu var mı?


Yanıtlar:


325

Komut dosyasının bulunduğu dosyada, böyle bir şey yapmak istersiniz:

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

Bu, aradığınız dosyanın mutlak yolunu verecektir. Setuptools kullanıyorsanız, bunun yerine muhtemelen paket kaynakları API'sını kullanmanız gerektiğini unutmayın .

GÜNCELLEME : Ben bir kod örneği yapıştırabilirsiniz böylece burada bir yorum yanıtlıyorum. :-)

__file__Her zaman mevcut olmayan düşüncede doğru muyum (örneğin dosyayı içe aktarmak yerine doğrudan çalıştırdığınızda)?

__main__Doğrudan dosyayı çalıştırdığından bahsettiğinizde script demek istediğinizi varsayıyorum . Öyleyse, sistemimde durum böyle görünmüyor (OS X 10.5.7'de python 2.5.1):

#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py

Ancak, __file__C uzantıları ile bazı tuhaflıklar olduğunu biliyorum . Örneğin, bunu Mac bilgisayarımda yapabilirim:

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

Ancak, bu Windows makinemde bir istisna oluşturur.


1
Dosyanın her zaman mevcut olmadığını düşünerek doğru muyum (örneğin dosyayı içe aktarmak yerine doğrudan çalıştırdığınızda)?
Stephen Edmonds

@Stephen Edmonds Onu içe aktarma yerine çalıştırdığım bir dosya kullanıyorum ve harika çalışıyor.
Baudtack

22
Taşınabilirlik için her yerde os.path.join kullanmanız gerektiğini unutmayın:filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')
ford

22
os.path.dirname(__file__)boş bir dize verebilir, os.path.dirname(os.path.abspath(__file__))bunun yerine kullanın
Dmitry Trofimov

14
Bu küçük bir şeydir, ancak LÜTFEN yerleşik olarak olduğu için dir değişken adı olarak kullanılmaz.
David

63

gerekir os.path.realpath(aşağıdaki örnek, üst dizini yolunuza ekler)

import sys,os
sys.path.append(os.path.realpath('..'))

2
os.path.dirname(__file__)bana boş bir ip verdi. Bu mükemmel çalıştı.
Darragh Enright

3
Bu, dizinin üst dizinine komut dosyasının konumundan değil, komut dosyasının çalıştırıldığı gibi görünür.
Coquelicot

10
os.path.realpath('..')size geçerli çalışma dizininin üst dizinini verir . Genellikle istediğiniz şey bu değildir .
Martijn Pieters

1
@DarraghEnright: Bu yalnızca bir Python-script-exe paketleme ortamında gerçekleşir. Mevcut çalışma direktifine güvenmenin alternatif olacağı nadir istisnalardan biri budur.
Martijn Pieters

52

Kabul edilen cevapta belirtildiği gibi

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')

Sadece eklemek istiyorum

ikinci dize ters eğik çizgi ile başlayamaz, hiçbir dizge ters eğik çizgi içermemelidir

Gibi bir şey olmalı

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')

Kabul edilen cevap bazı durumlarda yanıltıcı olabilir, lütfen ayrıntılar için bu bağlantıya bakın


4
Evet os.path.join, işletim sistemine özgü ayırıcıyla birleştirildiği için kullanmak daha iyidir.
Farshid T

'/relative/path...'göreceli bir yol değildir. Bu kasıtlı mı?
steveire

Bu yanıt şimdi güncel değil, çünkü en üstteki cevap uygun bir göreceli yol kullanmak üzere düzenlendi os.path.join(). Geriye kalan, her bir yol elemanı için yol ayırıcıyı kodlamak yerine ayrı dizeler kullanma tercihidir.
Martijn Pieters

@MartijnPieters Evet, en iyi yanıt kısmen buna uyacak şekilde düzenlendi, ancak ayrı dizeler bir tercih değil - sokmaları bu şekilde ayırmak os'dan bağımsız olmasını sağlıyor.
jshrimp29

26

Şimdi 2018 ve Python __future__uzun zaman önce evrildi. Yani ne kadar şaşırtıcı kullanmayla ilgili pathlibgörevi başarmak için Python 3.4 ile gelen yerine mücadele os, os.path, glob, shutil, vb

Burada 3 yolumuz var (muhtemelen çoğaltılmış):

  • mod_path: basit yardımcı komut dosyasının yolu
  • src_path: kopyalanmayı bekleyen birkaç şablon dosyası içerir .
  • cwd: geçerli dizin , bu şablon dosyalarının hedefi.

ve sorun: Bizde olmayan tam yolunu src_path, sadece bilmek 's göreli yol için mod_path.

Şimdi bunu şaşırtıcı ile çözelim pathlib:

# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path

# `cwd`: current directory is straightforward
cwd = Path.cwd()

# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent

# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()

Gelecekte, bu kadar basit. : D


Ayrıca, bu şablon dosyalarını seçip kontrol edebilir ve kopyalayabilir / taşıyabiliriz pathlib:

if src_path != cwd:
    # When we have different types of files in the `src_path`
    for template_path in src_path.glob('*.ini'):
        fname = template_path.name
        target = cwd / fname
        if not target.exists():
            # This is the COPY action
            with target.open(mode='wb') as fd:
                fd.write(template_path.read_bytes())
            # If we want MOVE action, we could use:
            # template_path.replace(target)

14

Kodumu düşün:

import os


def readFile(filename):
    filehandle = open(filename)
    print filehandle.read()
    filehandle.close()



fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir

#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)

#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)

#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)

#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)

Bunu pencerelerde çalıştırdığımda bir hata alıyorum: FileNotFoundError: [Errno 2] Böyle bir dosya veya dizin yok: '<path>' burada <path> doğru yol parçalarına sahiptir, ancak ayırıcılar için \\ kullanır.
lonstar

11

Bkz. Sys.path Program başladıktan sonra başlatıldığı gibi, bu listenin ilk öğesi olan yol [0], Python yorumlayıcısını çağırmak için kullanılan komut dosyasını içeren dizindir.

Bu yolu , göreli yolunuzu uyguladığınız kök klasör olarak kullanın

>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'

3
Bu mutlaka doğru değildir. Genellikle sys.path [0], geçerli dizine göreceli yol olan boş bir dize veya noktadır. Geçerli dizini istiyorsanız, os.getcwd komutunu kullanın.
Jason Baker

Orijinal poster, geçerli çalışma dizininin göreli yolu temel almak için yanlış bir yer olduğunu belirtti. Sys.path [0] 'un her zaman geçerli olmadığını söylemekte haklısınız.
Tom Leys

Hayır, sys.path[0]her zaman üst dizine ayarlanmaz. Python kodu gömülü bir yorumlayıcıyla -cya -mda aracılığıyla çağrılabilir , bu noktada sys.path[0]tamamen farklı bir şeye ayarlanır.
Martijn Pieters

6

Kullanmak yerine

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

kabul edilen cevapta olduğu gibi, kullanımı daha sağlam olacaktır:

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

çünkü __file__ kullanılması modülün yüklendiği dosyayı döndürür, eğer bir dosyadan yüklenmişse, betiği olan dosya başka bir yerden çağrılırsa, döndürülen dizin doğru olmaz.

Bu cevaplar daha fazla ayrıntı veriyor: https://stackoverflow.com/a/31867043/5542253 ve https://stackoverflow.com/a/50502/5542253


5
inspect.stack()Bir olan pahalı çağırmak için işlev. Daha sonra atıp yalnızca en üstteki kareyi alacağınız tüm yığın kareleri için bilgi alır. Temelde inspect.getfile()sadece döndüren modül nesnesini çağırır module.__file__. Sadece kullanmaktan çok daha iyisin __file__.
Martijn Pieters

4

Merhaba öncelikle os.path.abspath (yol) ve os.path.relpath (yol) işlevlerini anlamalısınız

Kısacası os.path.abspath (yol) bir hale göreli yolu ile mutlak yol . Sağlanan yolun kendisi mutlak bir yolsa, işlev aynı yolu döndürür.

Benzer os.path.relpath (yol) bir hale getirir mutlak yolunu için göreli yolu . Sağlanan yolun kendisi göreceli bir yolsa, işlev aynı yolu döndürür.

Aşağıdaki örnek, yukarıdaki kavramı doğru bir şekilde anlamanıza izin verebilir :

python betiğim tarafından işlenecek girdi dosyalarının listesini içeren bir input_file_list.txt dosyanız olduğunu varsayalım .

D: \ konsantre \ input1.dic

D: \ konsantre \ input2.dic

D: \ Copyioconc \ input_file_list.txt

Yukarıdaki klasör yapısını görürseniz , Copy_conc klasöründe input_file_list.txt dosyası ve python betiği tarafından işlenecek dosyalar conc klasöründe bulunur

Ancak input_file_list.txt dosyasının içeriği aşağıda gösterilmiştir:

.. \ kons \ input1.dic

.. \ kons \ input2.dic

Python betiğim de D: drive'de.

Ve input_file_list.txt dosyasında sağlanan göreli yol input_file_list.txt dosyasının yoluna göredir .

Python betiği geçerli çalışma dizinini yürüttüğünde ( yolu almak için os.getcwd () kullanın)

Benim göreli yolu göreli olduğundan input_file_list.txt , yani : "\ Copyofconc D" i geçerli çalışma dizini değiştirmek zorunda ": \ Copyofconc D" .

Bu yüzden os.chdir ('D: \ Copyofconc') kullanmalıyım , böylece geçerli çalışma dizini "D: \ Copyofconc" olmalıdır .

Şimdi input1.dic ve input2.dic dosyalarını almak için ".. \ conc \ input1.dic" satırlarını okuyacağım ve

input1_path = os.path.abspath ('.. \ conc \ input1.dic') (mutlak yola göreli yolu değiştirmek için. Burada geçerli çalışma dizini "D: \ Copyofconc", ". \ conc \ input1 dosyasıdır. dic "e" D: \ Copyofconc "ile ilgili olarak erişilir)

bu nedenle input1_path "D: \ conc \ input1.dic" olmalıdır


4

Bu kod, ana komut dosyasının mutlak yolunu döndürür.

import os
def whereAmI():
    return os.path.dirname(os.path.realpath(__import__("__main__").__file__))

Bu bir modülde bile çalışacaktır.


Yeniden içe aktarmak yerine kullanırsınız sys.modules['__main__'].__file__.
Martijn Pieters

3

Benim için çalışan bir alternatif:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

0

Benim için işe yarayan kullanmak sys.path.insert. Sonra gitmem gereken dizini belirledim. Mesela sadece bir dizine çıkmam gerekiyordu.

import sys
sys.path.insert(0, '../')

1
Bu, gerçekte istediğinizden kökten farklı olabilecek geçerli çalışma dizinine dayanır.
Martijn Pieters

-2

Bunun bazı eski sürümler için geçerli olup olmadığından emin değilim, ancak Python 3.3'ün yerel göreli yol desteğine sahip olduğuna inanıyorum.

Örneğin, aşağıdaki kod python komut dosyasıyla aynı klasörde bir metin dosyası oluşturmalıdır:

open("text_file_name.txt", "w+t")

(göreceli bir yolsa başlangıçta ileri veya ters eğik çizgi olmaması gerektiğini unutmayın)


Evet, bu OP'nin istediği CWD'den çalışacaktır. Komut dosyalarının bulunduğu yerden çalışmak istemek.
Samy Bencherif
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.