이 경우 os.path.join ()이 작동하지 않는 이유는 무엇입니까?


325

아래 코드는 디버그 할 때 명령이 전체 경로를 저장하지 않고 마지막 항목 만 저장하지 않습니다.

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

이것을 테스트 할 때 /new_sandbox/코드 의 일부만 저장합니다 .

답변:


426

후자의 문자열은 슬래시로 시작해서는 안됩니다. 슬래시로 시작하면 "절대 경로"로 간주되며 그 이전의 모든 항목은 삭제됩니다.

파이썬 문서os.path.join 인용 :

구성 요소가 절대 경로 인 경우 이전의 모든 구성 요소가 버리고 절대 경로 구성 요소에서 결합이 계속됩니다.

Windows에서 드라이브 문자와 관련된 동작은 이전 Python 버전과 비교하여 변경된 것으로 보입니다.

Windows에서 절대 경로 구성 요소 (예 :) r'\foo'가 발생 하면 드라이브 문자가 재설정되지 않습니다 . 구성 요소에 드라이브 문자가 포함되어 있으면 이전의 모든 구성 요소가 버리고 드라이브 문자가 재설정됩니다. 각 드라이브 os.path.join("c:", "foo")에 대한 현재 디렉토리가 있으므로 ,가 아닌 드라이브 C:( c:foo) 의 현재 디렉토리에 상대적인 경로를 나타냅니다 c:\foo.


85
-1 : "/"를 포함하는 문자열이 없습니다 . os.path.join의 전체 요점은 경로에 슬래시가 들어 가지 않도록하는 것입니다.
S.Lott December

6
str.join ()의 문제점은 물론 이중 슬래시를 제거하지 않는다는 것입니다. 이것이 os.path.join을 사용하는 사람들의 주요 목적이라고 생각합니다. 예 '/'.join(['/etc/', '/ CONT']) 세 결과 슬래시 '/ 등의 conf ///'
더스틴 Rasener

17
@DustinRasener os.path.normpath목표를 달성하는 데 사용할 수 있습니다 .
Gareth Latty

5
왜 사람들이 os.path.join 동작에 좌절하는지 전혀 알 수 없습니다. 다른 언어에서는 동등한 경로 결합 라이브러리 / 방법이 동일하게 동작합니다. 더 안전하고 더 합리적입니다.
Don Cheadle

19
"명시적인 것이 암시적인 것보다 낫다" 는 기본적인 추론 과 는 달리, 암시적인 마술 이기 때문에 이것은 실망 스럽다 . 그리고 그것은 입니다 . 언어 설계자들은 자신들이 더 잘 알고 있다고 생각할 수도 있지만, 때때로 이것을하고 싶은 분명하고 명백한 이유가 있습니다. 이제는 할 수 없습니다. 이것이 우리가 좋은 것을 가질 수없는 이유입니다.
세실 커리

151

아이디어는 os.path.join()프로그램을 크로스 플랫폼 (linux / windows / etc)으로 만드는 것입니다.

슬래시조차도 그것을 망칩니다.

같은 기준점의 일종으로 사용되는 경우에만 의미가 그래서 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기본적인 str 메소드 대신 사용의 요점은 글쓰기를 피하는 것 /입니다. 모든 서브 디렉토리를 새로운 인수로두고 슬래시를 모두 제거하는 것도 좋습니다. todaystr슬래시로 시작하지 않는 확인으로 확인하는 것이 좋습니다 . ;)
스누즈 92

3
이것은 Windows에서도 작동합니다 (python 2.7.6). 'C : \'를 방해하지 않고 하위 디렉토리에 합류했습니다.
rickfoosusa


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

그 다음 myapp 해야 에 설정 파일을 사용 /some/path/bar.conf(그리고 /etc/myapp.conf/some/path/bar.conf또는 이와 유사한 것).

그것은 좋지 않을 수도 있지만 이것이 절대 경로 행동의 동기라고 생각합니다.


감사! 나는 당신의 대답을 읽을 때까지 항상이 행동을 싫어했습니다! docs.python.org/3.5/library/os.path.html#os.path.join에 설명되어 있지만 동기 부여는 아닙니다.
Eli_B

많은 사람들이 끔찍하다고 생각하는 솔루션이 필요한 순간입니다.
ashrasmun

12

왜냐하면 당신 '/new_sandbox/'은 a로 시작 /해서 루트 디렉토리에 상대적인 것으로 가정하기 때문입니다. 선행을 제거하십시오 /.


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)

비록 extension수 있습니다 .jpg당신이 "는 foobar"가 아니라 "foobar.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

두 번째 문자열과 다음 문자열에서 string을 제거하여 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"... 나는 그 의도 된 결과 의심.
NichtJens

1
업데이트 됨-실행중인 OS의 경로와 독립적으로 로컬에서 사용하는 경로 sep로 힌트를 제공해야한다고 가정합니다.
Neil McGill

1
예. 또는 하나는 일반적으로 사용되는 두 옵션으로 나눌 수 있지만 다른 OS는 1/3을 얻을 수 있습니다.
NichtJens
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.