How does os.path.join() work?

MacOS

Question or issue on macOS:

Please help me understand how the builtin os.path.join() function works. For example:

import os
print os.path.join('cat','dog') # 'cat/dog' no surprise here
print os.path.join('cat','dog').join('fish') # 'fcat/dogicat/dogscat/dogh'

On Mac (and i guess linux too) os.name is an alias for posixpath. So looking into the posixpath.py module, the join() function looks like this:

def join(a, *p):
"""Join two or more pathname components, inserting '/' as needed.
If any component is an absolute path, all previous path components
will be discarded.  An empty last part will result in a path that
ends with a separator."""
path = a
for b in p:
    if b.startswith('/'):
        path = b
    elif path == '' or path.endswith('/'):
        path +=  b
    else:
        path += '/' + b
return path

So join() returns a string. Why does os.path.join(‘something’).join(‘something else’) even work? Shouldn’t it raise something like ‘str’ object has no attribute ‘join’? I mean if I copy the function some other place and call it like renamed_join(‘foo’,’bar’) it works as expected but if i do renamed_join(‘foo’,’bar’).renamed_join(‘foobar’) will raise an AttributeError as expected. Hopefully this is not a very stupid question. It struck me just when I thought I was starting to understand python…

How to solve this problem?

Solution no. 1:

You can’t chain os.path.join like that. os.path.join returns a string; calling the join method of that calls the regular string join method, which is entirely unrelated.

Solution no. 2:

Your second join call is not os.path.join, it is str.join. What this one does is that it joins the argument (as an iterable, meaning it can be seen as f, i, s, h) with self as the separator (in your case, cat/dog)

So basically, is puts cat/dog between every letter of fish.

Because str has a join attribute.

Hope this helps!