इस मामले में os.path.join () काम क्यों नहीं करता है?


325

नीचे दिया कोड शामिल नहीं होगा, जब डिबग किया गया कमांड पूरे रास्ते को स्टोर नहीं करता है, लेकिन सिर्फ अंतिम प्रविष्टि है।

os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/')

जब मैं इसका परीक्षण करता हूं तो यह केवल /new_sandbox/कोड का हिस्सा संग्रहीत करता है ।

जवाबों:


426

बाद के तार एक स्लैश से शुरू नहीं होने चाहिए। यदि वे एक स्लैश के साथ शुरू करते हैं, तो उन्हें "निरपेक्ष पथ" माना जाता है और उनके त्यागने से पहले सब कुछ।

इसके लिए पायथन डॉक्स काos.path.join हवाला देते हुए :

यदि एक घटक एक पूर्ण पथ है, तो पिछले सभी घटकों को फेंक दिया जाता है और निरपेक्ष पथ घटक से जुड़ना जारी रहता है।

विंडोज पर ध्यान दें, ड्राइव अक्षर के संबंध में व्यवहार, जो पहले पायथन संस्करणों की तुलना में बदल गया लगता है:

जब कोई पूर्ण पथ घटक (जैसे r'\foo') का सामना होता है , तो विंडोज पर, ड्राइव अक्षर को रीसेट नहीं किया जाता है। यदि किसी घटक में ड्राइव अक्षर है, तो पिछले सभी घटकों को फेंक दिया जाता है और ड्राइव अक्षर रीसेट हो जाता है। ध्यान दें कि चूंकि प्रत्येक ड्राइव के लिए एक वर्तमान निर्देशिका है, इसलिए os.path.join("c:", "foo")ड्राइव पर वर्तमान निर्देशिका के सापेक्ष पथ का प्रतिनिधित्व करता है C:( c:foo), नहीं c:\foo


85
-1: किसी स्ट्रिंग में "/" शामिल नहीं होना चाहिए। Os.path.join का एक संपूर्ण बिंदु पथ में किसी भी स्लैश को रोकने के लिए है।
एस.लॉट

6
Str.join () के साथ समस्या, ज़ाहिर है, कि यह डबल स्लैश को समाप्त नहीं करेगा। मुझे लगता है कि यह os.path.join का उपयोग करने वाले लोगों के लिए प्राथमिक उद्देश्य है। जैसे '/'.join( (''/cc/', '/ conf']) का परिणाम तीन
स्लैशों में होता है

17
@DustinRasener आप os.path.normpathउस उद्देश्य को प्राप्त करने के लिए उपयोग कर सकते हैं ।
गारेथ लैटी

5
कोई सुराग नहीं है कि लोग os.path.join व्यवहार को लेकर निराश क्यों हैं। अन्य भाषाओं में, समान पथ-जुड़ने वाली लाइब्रेरी / विधि सटीक व्यवहार करती है। यह सुरक्षित है, और अधिक समझ में आता है।
डॉन चेदिले

19
यह निराशाजनक है क्योंकि यह अंतर्निहित जादू है , "स्पष्ट से अधिक स्पष्ट है" के कार्डिनल अनुमान के विपरीत । और यह है । भाषा डिजाइनर विश्वास कर सकते हैं कि वे बेहतर जानते हैं, लेकिन कभी-कभी ऐसा करने के लिए स्पष्ट और प्रदर्शनकारी सुरक्षित कारण मौजूद हैं। अब हम नहीं कर सकते। यही कारण है कि हमारे पास अच्छी चीजें नहीं हो सकती हैं।
सेसिल करी

151

os.path.join()अपने कार्यक्रम को क्रॉस-प्लेटफ़ॉर्म (लिनक्स / विंडोज़ / आदि) बनाने का विचार है।

यहां तक ​​कि एक स्लैश भी इसे बर्बाद कर देता है।

तो यह केवल समझ में आता है जब किसी तरह के संदर्भ बिंदु के साथ os.environ['HOME']या जैसे का उपयोग किया जा रहा है os.path.dirname(__file__)


75

os.path.join()os.path.sepरिश्तेदार पथ के बजाय एक पूर्ण बनाने के लिए संयोजन के रूप में इस्तेमाल किया जा सकता है ।

os.path.join(os.path.sep, 'home','build','test','sandboxes',todaystr,'new_sandbox')

8
os.path.sepनिरपेक्ष पथ बनाने के लिए पहले तत्व के रूप में उपयोग यहाँ किसी भी अन्य उत्तर से बेहतर है! os.pathमूल आवधिक तरीकों के बजाय उपयोग करने का संपूर्ण बिंदु लेखन से बचना है /। हर उपनिर्देशिका को एक नए तर्क के रूप में रखना और सभी स्लैश को दूर करना भी बहुत अच्छा है। यह शायद एक अच्छा विचार है कि एक चेक के साथ सुनिश्चित करें कि todaystrएक स्लैश से शुरू नहीं होता है! ;)
snooze92

3
यह विंडोज़ पर भी काम करता है (अजगर 2.7.6)। यह 'C: \' के साथ पूर्ण नहीं हुआ और उपनिर्देशिकाओं में शामिल हो गया।
rickfoosusa

23

रूट निर्देशिका की शुरुआत करते हुए, पथ घटकों की शुरुआत में फ़ॉरवर्ड स्लैश का उपयोग न करें:

os.path.join('/home/build/test/sandboxes', todaystr, 'new_sandbox')

इसे भी देखें: http://docs.python.org/library/os.path.html#os.path.join


21

यह समझने में मदद करने के लिए कि यह आश्चर्यजनक व्यवहार पूरी तरह से भयानक क्यों नहीं है , एक आवेदन पर विचार करें जो एक तर्क के रूप में एक कॉन्फ़िगर फ़ाइल नाम को स्वीकार करता है:

config_root = "/etc/myapp.conf/"
file_name = os.path.join(config_root, sys.argv[1])

यदि आवेदन के साथ निष्पादित किया जाता है:

$ myapp foo.conf

कॉन्फ़िगर फ़ाइल /etc/myapp.conf/foo.confका उपयोग किया जाएगा।

लेकिन विचार करें कि क्या होता है यदि आवेदन को इसके साथ बुलाया जाता है:

$ myapp /some/path/bar.conf

फिर (और नहीं या समान) पर config फ़ाइल का उपयोग myapp करना चाहिए/some/path/bar.conf/etc/myapp.conf/some/path/bar.conf

यह महान नहीं हो सकता है, लेकिन मेरा मानना ​​है कि यह पूर्ण पथ व्यवहार के लिए प्रेरणा है।


धन्यवाद! मुझे आपके उत्तर को पढ़ने तक इस व्यवहार से हमेशा नफरत थी! यह docs.python.org/3.5/library/os.path.html#os.path.join में प्रलेखित है , लेकिन इसके लिए प्रेरणा नहीं है।
एली_बिन

यह क्षण जब आपको बिल्कुल समाधान की आवश्यकता होती है तो बहुत से लोग भयानक के रूप में देखते हैं।
आश्रममुन

12

ऐसा इसलिए है क्योंकि आपकी '/new_sandbox/'शुरुआत एक के साथ होती है /और इस तरह इसे रूट डायरेक्टरी के सापेक्ष माना जाता है। अग्रणी निकालें /


8

अपने कार्य को अधिक पोर्टेबल बनाने के लिए, इसे इस प्रकार उपयोग करें:

os.path.join(os.sep, 'home', 'build', 'test', 'sandboxes', todaystr, 'new_sandbox')

या

os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, 'new_sandbox')

8

का कॉम्बो प्रयास करें split("/")और *मौजूदा मिलती है साथ तार के लिए।

import os

home = '/home/build/test/sandboxes/'
todaystr = '042118'
new = '/new_sandbox/'

os.path.join(*home.split("/"), todaystr, *new.split("/"))


यह काम किस प्रकार करता है...

split("/") मौजूदा पथ को सूची में बदल देता है: ['', 'home', 'build', 'test', 'sandboxes', '']

* सूची के सामने सूची के प्रत्येक आइटम का अपना पैरामीटर टूट जाता है


3

के साथ new_sandboxही प्रयास करें

os.path.join('/home/build/test/sandboxes/', todaystr, 'new_sandbox')

2

इसे इस तरह से करें, बिना अतिरिक्त स्लैश के

root="/home"
os.path.join(root,"build","test","sandboxes",todaystr,"new_sandbox")

0

ध्यान दें कि एक समान समस्या आपको काट सकती है यदि आप os.path.join()एक एक्सटेंशन को शामिल करने के लिए उपयोग करते हैं जिसमें पहले से ही एक डॉट शामिल है, जो कि आपके द्वारा उपयोग किए जाने पर स्वचालित रूप से होता है os.path.splitext()। इस उदाहरण में:

components = os.path.splitext(filename)
prefix = components[0]
extension = components[1]
return os.path.join("avatars", instance.username, prefix, extension)

भले ही आप "foobar.jpg" नामक फाइल के बजाय "फोब्बर" नामक फ़ोल्डर के साथ समाप्त extensionहो सकते हैं .jpg। इसे रोकने के लिए आपको एक्सटेंशन को अलग से जोड़ना होगा:

return os.path.join("avatars", instance.username, prefix) + extension

0

आप यह कर सकते stripहैं '/':

>>> os.path.join('/home/build/test/sandboxes/', todaystr, '/new_sandbox/'.strip('/'))
'/home/build/test/sandboxes/04122019/new_sandbox'

0

मैं दूसरी और निम्न स्ट्रिंग से स्ट्रिप करने की सलाह os.path.sepदूंगा, जिससे उन्हें पूर्ण पथ के रूप में व्याख्या करने से रोका जा सके:

first_path_str = '/home/build/test/sandboxes/'
original_other_path_to_append_ls = [todaystr, '/new_sandbox/']
other_path_to_append_ls = [
    i_path.strip(os.path.sep) for i_path in original_other_path_to_append_ls
]
output_path = os.path.join(first_path_str, *other_path_to_append_ls)

0
os.path.join("a", *"/b".split(os.sep))
'a/b'

एक फुलर संस्करण:

import os

def join (p, f, sep = os.sep):
    f = os.path.normpath(f)
    if p == "":
        return (f);
    else:
        p = os.path.normpath(p)
        return (os.path.join(p, *f.split(os.sep)))

def test (p, f, sep = os.sep):
    print("os.path.join({}, {}) => {}".format(p, f, os.path.join(p, f)))
    print("        join({}, {}) => {}".format(p, f, join(p, f, sep)))

if __name__ == "__main__":
    # /a/b/c for all
    test("\\a\\b", "\\c", "\\") # optionally pass in the sep you are using locally
    test("/a/b", "/c", "/")
    test("/a/b", "c")
    test("/a/b/", "c")
    test("", "/c")
    test("", "c")

क्या होगा अगर os.sep वास्तव में है "\"? फिर आपका पहला उदाहरण बनता है os.path.join("a", *"/b".split("\\")), जो पैदावार करता है "/b"... मुझे संदेह है कि इसका इच्छित परिणाम है।
निक्टजेंस

1
अपडेट किया गया - मुझे लगता है कि आपको उस सेप के रूप में एक संकेत देना होगा जिसे आप स्थानीय रूप से उस ओएस से स्वतंत्र उपयोग कर रहे हैं जिस पर आप चल रहे हैं
नील मैकगिल

1
हाँ। वैकल्पिक रूप से एक आमतौर पर इस्तेमाल किए जाने वाले दोनों विकल्पों पर विभाजित हो सकता है ... लेकिन फिर कुछ अन्य ओएस एक तिहाई के साथ आ सकते हैं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.