141

I can do

>>> os.path.join("c:/","home","foo","bar","some.txt")
'c:/home\\foo\\bar\\some.txt'

But, when I do

>>> s = "c:/,home,foo,bar,some.txt".split(",")
>>> os.path.join(s)
['c:/', 'home', 'foo', 'bar', 'some.txt']

What am I missing here?

ATOzTOA
  • 34,814
  • 22
  • 96
  • 117

5 Answers5

251

The problem is, os.path.join doesn't take a list as argument, it has to be separate arguments.

To unpack the list into separate arguments required by join (and for the record: list was obtained from a string using split), use * - or the 'splat' operator, thus:

>>> s = "c:/,home,foo,bar,some.txt".split(",")
>>> os.path.join(*s)
'c:/home\\foo\\bar\\some.txt'
mirekphd
  • 4,799
  • 3
  • 38
  • 59
ATOzTOA
  • 34,814
  • 22
  • 96
  • 117
  • 13
    some more context for splat: https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists – A.Wan Jun 02 '14 at 20:28
  • 4
    Note that I tried to use this to remove the last part of a full path. It resulted in an [error](http://stackoverflow.com/questions/31693272/errno-2-using-python-shutil-py-no-such-file-or-directory-for-file-destination) (in Mac), as it was missing the first slash at `/Users/...`. To solve it, I added that leading slash manually, in case somebody faces the same problem... – J0ANMM Nov 15 '16 at 17:50
32

Assuming join wasn't designed that way (which it is, as ATOzTOA pointed out), and it only took two parameters, you could still use the built-in reduce:

>>> reduce(os.path.join,["c:/","home","foo","bar","some.txt"])
'c:/home\\foo\\bar\\some.txt'

Same output like:

>>> os.path.join(*["c:/","home","foo","bar","some.txt"])
'c:/home\\foo\\bar\\some.txt' 

Just for completeness and educational reasons (and for other situations where * doesn't work).

Hint for Python 3

reduce was moved to the functools module.

Aviv Cohn
  • 15,543
  • 25
  • 68
  • 131
Thorsten Kranz
  • 12,492
  • 2
  • 39
  • 56
18

I stumbled over the situation where the list might be empty. In that case:

os.path.join('', *the_list_with_path_components)

Note the first argument, which will not alter the result.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • os.path.join('', *the_list_with_path_components) is not adding the leading slash in python 2.7, i am curious how can i preserve this slash – masky007 Apr 29 '22 at 13:07
11

It's just the method. You're not missing anything. The official documentation shows that you can use list unpacking to supply several paths:

s = "c:/,home,foo,bar,some.txt".split(",")
os.path.join(*s)

Note the *s intead of just s in os.path.join(*s). Using the asterisk will trigger the unpacking of the list, which means that each list argument will be supplied to the function as a separate argument.

gaborous
  • 15,832
  • 10
  • 83
  • 102
Greg
  • 5,422
  • 1
  • 27
  • 32
2

This can be also thought of as a simple map reduce operation if you would like to think of it from a functional programming perspective.

import os
folders = [("home",".vim"),("home","zathura")]
[reduce(lambda x,y: os.path.join(x,y), each, "") for each in folders]

reduce is builtin in Python 2.x. In Python 3.x it has been moved to itertools However the accepted the answer is better.

This has been answered below but answering if you have a list of items that needs to be joined.

Nishant
  • 20,354
  • 18
  • 69
  • 101