Python os.path.join () en una lista

97

puedo hacer

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

Pero cuando lo hago

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

What am I missing here?

ATOzTOA
fuente

Respuestas:

197

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

This is where *, the 'splat' operator comes into play...

I can do

>>> s = "c:/,home,foo,bar,some.txt".split(",")
>>> os.path.join(*s)
'c:/home\\foo\\bar\\some.txt'
ATOzTOA
fuente
10
some more context for splat: docs.python.org/2/tutorial/…
A.Wan
3
Note that I tried to use this to remove the last part of a full path. It resulted in an error (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
23

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.

Thorsten Kranz
fuente
2
In Python 3 reduce was moved to functools module in case anyone else was looking for it as I was.
Adam Badura
Thank you for the hint, I'll adjust my answer.
Thorsten Kranz
3
pity that python walks more and more away from functional style instead of embracing it and opening up. moving reduce away to a module is a statement.
SHernandez
Even in 2.7 one can from functools import reduce
duhaime
14

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
fuente
8

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.

Greg
fuente
Better look into your link once more ;-)
Thorsten Kranz
@Greg it is prefered on SO to copy the relevant parts into the answer and not just paste a link, maybe therefore the downvotes
SHernandez
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
fuente