पायथन में सापेक्ष पथ


245

मैं काम के लिए एक सरल सहायक स्क्रिप्ट का निर्माण कर रहा हूं जो हमारे कोड बेस में कुछ फाइलों को वर्तमान निर्देशिका में कॉपी करेगा। हालाँकि, मुझे उस निर्देशिका का पूर्ण पथ नहीं है जहाँ टेम्पलेट संग्रहीत हैं। मेरे पास स्क्रिप्ट से एक सापेक्ष पथ है, लेकिन जब मैं स्क्रिप्ट को कॉल करता हूं तो यह व्यवहार करता है कि वर्तमान कार्य निर्देशिका के सापेक्ष पथ के रूप में। क्या यह निर्दिष्ट करने का कोई तरीका है कि यह सापेक्ष URL स्क्रिप्ट के स्थान से है?


जवाबों:


325

स्क्रिप्ट वाली फ़ाइल में, आप ऐसा कुछ करना चाहते हैं:

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

यह आपको उस फ़ाइल का संपूर्ण मार्ग देगा जिसे आप खोज रहे हैं। ध्यान दें कि यदि आप सेटपूल का उपयोग कर रहे हैं, तो आपको संभवतः इसके बजाय पैकेज संसाधनों एपीआई का उपयोग करना चाहिए ।

अद्यतन : मैं यहाँ एक टिप्पणी का जवाब दे रहा हूँ ताकि मैं एक कोड नमूना पेस्ट कर सकूँ। :-)

क्या मैं यह सोचने में सही हूं कि __file__हमेशा उपलब्ध नहीं है (जैसे जब आप फ़ाइल को आयात करने के बजाय सीधे चलाते हैं)?

__main__जब आप सीधे फाइल चलाने का उल्लेख करते हैं , तो मैं आपको स्क्रिप्ट का मतलब समझा रहा हूं । यदि ऐसा है, तो मेरे सिस्टम पर ऐसा प्रतीत नहीं होता है (OS X 10.5.7 पर अजगर 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

हालांकि, मुझे पता है कि __file__सी एक्सटेंशन पर कुछ विचित्रताएं हैं । उदाहरण के लिए, मैं अपने मैक पर यह कर सकता हूं:

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

हालाँकि, यह मेरी विंडोज मशीन पर एक अपवाद को बढ़ाता है।


1
क्या मैं यह सोचने में सही हूं कि फ़ाइल हमेशा उपलब्ध नहीं होती है (जैसे जब आप फ़ाइल को आयात करने के बजाय सीधे चलाते हैं)?
स्टीफन एडमंड्स

@ स्टेपेन एडमंड्स मैं इसे एक फाइल का उपयोग कर रहा हूं जिसे मैं आयात करने के बजाय चलाता हूं, और यह बहुत अच्छा काम करता है।

22
ध्यान दें कि पोर्टेबिलिटी के लिए आपको हर जगह os.path.join का उपयोग करना चाहिए:filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')
ford

22
os.path.dirname(__file__)एक खाली स्ट्रिंग दे सकते हैं, os.path.dirname(os.path.abspath(__file__))इसके बजाय का उपयोग करें
दिमित्री ट्रोफिमोव

14
यह एक छोटी सी बात है, लेकिन कृपया एक चर नाम के रूप में dir का उपयोग न करें क्योंकि यह एक बिल्डिन है।
डेविड

63

आपको आवश्यकता है os.path.realpath(नीचे दिया गया नमूना आपके पथ में मूल निर्देशिका जोड़ता है)

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

2
os.path.dirname(__file__)मुझे एक खाली तार दिया। यह पूरी तरह से काम किया।
दरगाह

3
ऐसा लगता है कि स्क्रिप्ट के स्थान से नहीं, निर्देशिका का मूल भाग दिया जाता है।
Coquelicot

10
os.path.realpath('..')आपको वर्तमान कामकाजी निर्देशिका की मूल निर्देशिका प्रदान करता है । आमतौर पर वह नहीं होता जो आप चाहते हैं।
मार्टिज़न पीटर

1
@DarraghEnright: यह केवल पायथन-स्क्रिप्ट-टू-एक्स पैकेजिंग वातावरण में होता है। यह दुर्लभ अपवादों में से एक है, जहां मौजूदा कामकाजी डायर पर निर्भर रहना वैकल्पिक होगा।
मार्टिन पीटर्स

52

जैसा कि स्वीकृत उत्तर में बताया गया है

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

मैं बस उसे जोड़ना चाहता हूं

बाद वाला स्ट्रिंग बैकस्लैश के साथ शुरू नहीं हो सकता है, बिना किसी स्ट्रिंग को बैकस्लैश के शामिल नहीं करना चाहिए

यह कुछ ऐसा होना चाहिए

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

स्वीकृत उत्तर कुछ मामलों में भ्रामक हो सकता है, कृपया विवरण के लिए इस लिंक को देखें


4
हां का उपयोग os.path.joinकरना बेहतर है क्योंकि यह उन्हें ओएस-विशिष्ट विभाजक के साथ जोड़ता है।
फर्षिद टी

'/relative/path...'कोई सापेक्ष मार्ग नहीं है। क्या वह जानबूझकर है?
फ़ेयरवीर

यह उत्तर अब पुराना हो गया है, क्योंकि शीर्ष उत्तर को एक उचित सापेक्ष पथ का उपयोग करने के लिए संपादित किया गया है os.path.join()। जो बचा है वह पथ विभाजक को हार्डकोडिंग पर प्रत्येक पथ तत्व के लिए अलग-अलग तारों का उपयोग करने की प्राथमिकता है।
मार्टिन पीटर्स

@MartijnPieters हां, शीर्ष उत्तर को इस भाग में मिलान करने के लिए संपादित किया गया है, लेकिन अलग-अलग तार एक प्राथमिकता नहीं है - इस तरह से डंक को अलग करना इसे ओएस-स्वतंत्र बनाता है।
jrrimp29

26

यह अब 2018 है, और अजगर __future__लंबे समय पहले ही विकसित हो चुके हैं । तो कैसे अद्भुत प्रयोग के बारे में pathlibअजगर 3.4 के साथ आने वाले कार्य को पूरा करने के बजाय के साथ संघर्ष कर os, os.path, glob, shutil, आदि

तो हमारे यहाँ 3 रास्ते हैं (संभवतः डुप्लिकेट):

  • mod_path: जो सरल सहायक स्क्रिप्ट का मार्ग है
  • src_path: जिसमें कॉपी किए जाने की प्रतीक्षा कर रहे कुछ टेम्प्लेट फ़ाइल शामिल हैं
  • cwd: वर्तमान निर्देशिका , उन टेम्पलेट फ़ाइलों का गंतव्य।

और समस्या यह है: हमारे पास पूर्ण पथ नहीं है src_path, केवल यह जानें कि यह सापेक्ष पथ है mod_path

अब इसे अद्भुत के साथ हल करें 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()

भविष्य में, यह सिर्फ इतना आसान है। : डी


इसके अलावा, हम चुन सकते हैं और उन टेम्प्लेट फ़ाइलों की जांच और कॉपी / स्थानांतरित कर सकते हैं 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

मेरे कोड पर विचार करें:

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)

जब मैं इसे विंडोज़ में चलाता हूं, तो मैं एक त्रुटि प्राप्त करता हूं: FileNotFoundError: [Errno 2] ऐसी कोई फ़ाइल या निर्देशिका नहीं: '<पथ>' जहां <पथ> में सही पथ खंड हैं, लेकिन विभाजकों के लिए \\ का उपयोग करता है।
लोनस्टार

11

Sys.path देखें कार्यक्रम स्टार्टअप पर आरंभिक रूप से, इस सूची का पहला आइटम, पथ [0], वह निर्देशिका है जिसमें स्क्रिप्ट शामिल है जिसका उपयोग पायथन दुभाषिया को आमंत्रित करने के लिए किया गया था।

इस पथ का उपयोग रूट फ़ोल्डर के रूप में करें जहाँ से आप अपने सापेक्ष पथ को लागू करते हैं

>>> 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
यह जरूरी नहीं कि सच हो। आमतौर पर sys.path [0] एक खाली स्ट्रिंग या एक डॉट है, जो वर्तमान निर्देशिका का एक सापेक्ष पथ है। यदि आप वर्तमान निर्देशिका चाहते हैं, तो os.getcwd का उपयोग करें।
जेसन बेकर

मूल पोस्टर में टिप्पणी की गई थी कि वर्तमान कामकाजी निर्देशिका रिश्तेदार पथ को आधार बनाने के लिए गलत जगह है। आप यह कहने में सही हैं कि sys.path [0] हमेशा मान्य नहीं होता है।
टॉम लेयस

नहीं, sys.path[0]हमेशा मूल निर्देशिका में सेट नहीं किया जाता है। पायथन कोड एक एम्बेडेड दुभाषिया के साथ -cया -mउसके माध्यम से लागू किया जा सकता है , जिस बिंदु sys.path[0]पर कुछ अलग करने के लिए पूरी तरह से सेट है।
मार्टिन पीटर्स

6

के बजाय का उपयोग करने का

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

स्वीकार किए गए उत्तर के रूप में, यह उपयोग करने के लिए अधिक मजबूत होगा:

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

क्योंकि __file__ का उपयोग करने से वह फ़ाइल वापस आ जाएगी जिसमें से मॉड्यूल लोड किया गया था, अगर यह एक फ़ाइल से लोड किया गया था, इसलिए यदि स्क्रिप्ट के साथ फ़ाइल कहीं और से कॉल की जाती है, तो दी गई निर्देशिका सही नहीं होगी।

ये उत्तर अधिक विस्तार देते हैं: https://stackoverflow.com/a/31867043/5542253 और https://stackoverflow.com/a/50502/5542253


5
inspect.stack()कॉल करने के लिए एक महंगा कार्य है। यह सभी स्टैक फ़्रेमों के लिए जानकारी पुनर्प्राप्त करता है, जिसे आप तब त्याग देते हैं और केवल इसके लिए शीर्ष प्राप्त करते हैं। यह मूल रूप inspect.getfile()से मॉड्यूल ऑब्जेक्ट पर कॉल करता है, जो सिर्फ रिटर्न करता है module.__file__। आप अभी तक का उपयोग कर के बेहतर हैं __file__
मार्टिन पीटर्स

4

हाय सब से पहले आप कार्य समझना चाहिए os.path.abspath (पथ) और os.path.relpath (पथ)

संक्षेप में os.path.abspath (पथ) निरपेक्ष पथ के लिए एक सापेक्ष पथ बनाता है । और यदि प्रदान किया गया मार्ग स्वयं एक पूर्ण पथ है तो फ़ंक्शन उसी पथ को वापस करता है।

इसी तरह os.path.relpath (पथ) सापेक्ष पथ को एक पूर्ण पथ बनाता है । और यदि प्रदान किया गया पथ स्वयं एक सापेक्ष पथ है, तो फ़ंक्शन उसी पथ को वापस करता है।

नीचे दिए गए उदाहरण से आप उपरोक्त अवधारणा को ठीक से समझ सकते हैं :

मान लीजिए कि मेरे पास एक फ़ाइल input_file_list.txt है जिसमें मेरी अजगर स्क्रिप्ट द्वारा संसाधित की जाने वाली इनपुट फ़ाइलों की सूची है।

डी: \ सान्द्र \ input1.dic

डी: \ सान्द्र \ input2.dic

डी: \ Copyioconc \ input_file_list.txt

आप फ़ोल्डर संरचना ऊपर देखते हैं, तो input_file_list.txt में मौजूद है Copyofconc अजगर स्क्रिप्ट द्वारा संसाधित किया जा करने के लिए फ़ोल्डर और फ़ाइलों में मौजूद हैं सान्द्र फ़ोल्डर

लेकिन फ़ाइल input_file_list.txt की सामग्री नीचे दी गई है:

.. \ सान्द्र \ input1.dic

.. \ सान्द्र \ input2.dic

और मेरी अजगर स्क्रिप्ट डी: ड्राइव में मौजूद है ।

और input_file_list.txt फ़ाइल में प्रदान किया गया सापेक्ष पथ input_file_list.txt के पथ के सापेक्ष है है।

इसलिए जब अजगर लिपि वर्तमान कार्यशील निर्देशिका का उपयोग करेगी (os.getcwd () का उपयोग करें ) मार्ग प्राप्त करने के लिए का

जैसा कि मेरा सापेक्ष पथ input_file_list.txt के सापेक्ष है , जो "D: \ Copyofconc" है , मुझे वर्तमान कार्य निर्देशिका को "D: \ Copyofconc" में बदलना होगा

इसलिए मुझे os.chdir ('D: \ Copyofconc') का उपयोग करना होगा , इसलिए वर्तमान कार्यशील निर्देशिका "D: \ Copyofconc" होगी

अब फाइल input1.dic और input2.dic प्राप्त करने के लिए , मैं लाइनों को पढ़ूंगा ".. \ conc \ input1.dic" तब कमांड का उपयोग करेगा

input1_path = os.path.abspath ('.. \ conc \ input1.dic') (सापेक्ष पथ को निरपेक्ष पथ में बदलने के लिए। यहां वर्तमान कार्य निर्देशिका के रूप में "D: \ Copyofconc", फ़ाइल "।" conc \ input1 है। dic "D: \ Copyofconc" के सापेक्ष पहुँचा जा सकेगा)

इसलिए input1_path "D: \ conc \ input1.dic" होगा


4

यह कोड मुख्य स्क्रिप्ट पर पूर्ण पथ लौटाएगा।

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

यह एक मॉड्यूल में भी काम करेगा।


पुन: आयात करने के बजाय, आप उपयोग करेंगे sys.modules['__main__'].__file__
मार्टिन पीटर्स

3

एक विकल्प जो मेरे लिए काम करता है:

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

0

मेरे लिए जो काम कर रहा है वह उपयोग कर रहा है sys.path.insert। फिर मैंने उस निर्देशिका को निर्दिष्ट किया जिसकी मुझे आवश्यकता थी। उदाहरण के लिए मुझे सिर्फ एक डायरेक्टरी में जाने की जरूरत थी।

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

1
यह वर्तमान कामकाजी निर्देशिका पर निर्भर करता है, जो वास्तव में आप जो चाहते हैं, उससे अलग हो सकता है।
मार्टिन पीटर्स

-2

मुझे यकीन नहीं है कि यह पुराने संस्करणों में से कुछ पर लागू होता है, लेकिन मेरा मानना ​​है कि पायथन 3.3 में मूल सापेक्ष पथ समर्थन है।

उदाहरण के लिए निम्न कोड को अजगर स्क्रिप्ट के समान फ़ोल्डर में एक पाठ फ़ाइल बनाना चाहिए:

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

(ध्यान दें कि यदि यह एक सापेक्षिक मार्ग है तो शुरुआत में आगे या पीछे नहीं होना चाहिए)


ठीक है, इसलिए यह CWD से काम करेगा जो ओपी से नहीं मांगता है। स्क्रिप्ट स्थान से काम करना चाहते हैं।
सैमी बेनचेरी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.