-->

How/where to use os.path.sep?

2019-02-18 11:32发布

问题:

os.path.sep is the character used by the operating system to separate pathname components.

But when os.path.sep is used in os.path.join(), why does it truncate the path?

Example:

Instead of 'home/python', os.path.join returns '/python':

>>> import os
>>> os.path.join('home', os.path.sep, 'python')
'/python'

I know that os.path.join() inserts the directory separator implicitly.

Where is os.path.sep useful? Why does it truncate the path?

回答1:

Where os.path.sep is usefull?

I suspect that it exists mainly because a variable like this is required in the module anyway (to avoid hardcoding), and if it's there, it might as well be documented. Its documentation says that it is "occasionally useful".

Why it truncates the path?

From the docs for os.path.join():

If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.

and / is an absolute path on *nix systems.



回答2:

Drop os.path.sep from the os.path.join() call. os.path.join() uses os.path.sep internally.

On your system, os.path.sep == '/' that is interpreted as a root directory (absolute path) and therefore os.path.join('home', '/', 'python') is equivalent to os.path.join('/', 'python') == '/python'. From the docs:

If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.



回答3:

As correctly given in the docstring of os.path.join -

Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components will be discarded.

Same is given in the docs as well -

os.path.join(path, *paths)

Join one or more path components intelligently. The return value is the concatenation of path and any members of *paths with exactly one directory separator (os.sep) following each non-empty part except the last, meaning that the result will only end in a separator if the last part is empty. If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.

When you give os.path.sep alone, it is considered as an absolute path to the root directory - / .

Please note , this is for unix/linux based os.path , which internally is posixpath . Though the same behavior is seen in windows os.path.join() .

Example -

>>> import os.path
>>> os.path.join.__doc__
"Join two or more pathname components, inserting '/' as needed.\n    If any component is an absolute path, all previous path components\n    will be discarded."


回答4:

Here's the snippet of code that is run if you are on a POSIX machine:

posixpath.py

# Join pathnames.
# Ignore the previous parts if a part is absolute.
# Insert a '/' unless the first part is empty or already ends in '/'.

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."""
    sep = _get_sep(a)
    path = a
    try:
        if not p:
            path[:0] + sep  #23780: Ensure compatible data type even if p is null.
        for b in p:
            if b.startswith(sep):
                path = b
            elif not path or path.endswith(sep):
                path += b
            else:
                path += sep + b
    except (TypeError, AttributeError, BytesWarning):
        genericpath._check_arg_types('join', a, *p)
        raise
    return path

Specifically, the lines:

        if b.startswith(sep):
            path = b

And, since os.path.sep definitely starts with this character, whenever we encounter it we throw out the portion of the variable path that has already been constructed and start over with the next element in p.



回答5:

But when os.path.sep is used in os.path.join() , why it truncates the path?

Quoting directly from the documentation of os.path.join

If a component is an absolute path, all previous components are thrown away and joining continues from the absolute path component.

So when you do:

os.path.join('home', os.path.sep, 'python')

os.path.sep returns '/' which is an absolute path, and so 'home' is thrown away and you get only '/python' as the output.

This can is also clear from the example:

>>> import os
>>> os.path.join('home','/python','kivy')
'/python/kivy'

Where os.path.sep is usefull?

os.path.sep or os.sep returns the character used by the operating system to separate pathname components. But again quoting from the docs:

Note that knowing this is not sufficient to be able to parse or concatenate pathnames — use os.path.split() and os.path.join() — but it is occasionally useful.