The version of Python3.6 is planned (nevertheless, this is not explicitly mentioned anywhere, except for the line "Python-Version") the release of a new magic method __fspath__ ( https://www.python.org/dev/peps/pep-0519 ). The description seems clear:

It is an easy way to find out how to complete your path.

The goal is to make it easier for users to move to advanced objects representing file paths, while providing a convenient way to work with code that expects unicode or byte strings.

However, several points are not entirely clear:

Who is this update for? What users are we talking about? What would be a typical use case, whether in libraries or in application programs?

Usually, as an ordinary user, I write something like:

 project_path = os.path.realpath(os.path.dirname(__file__)) config_path = os.path.join(project_path, 'configs', 'sub_configs', 'my_super_config.ini') conf = open(config_path, 'r', encoding="utf-8") 

and I see no reason to create because of this separate classes representing paths. Even if these are classes like ConfigPath, ConcreteProjectConfigPath, it’s not quite clear where and why you can cram a new method.

    2 answers 2

    Because the call to str(path) fraught with errors. str(obj) works for any object in Python, but not all objects represent paths . An example from PEP 519 : open(str(None), 'w') can silently create a file instead of throwing an error. os.fspath(path) returns a path representation suitable for the file system and avoids silent errors:

     >>> import os >>> os.fspath(None) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: expected str, bytes or os.PathLike object, not <class 'NoneType' at ...> 

    Examples of candidates for the __fspath__ protocol: pathlib.Path , os.DirEntry (generated by os.scandir() ).


    Your example, you can rewrite it:

     from pathlib import Path import appdirs # $ pip install appdirs path = Path(appdirs.user_data_dir(appname, appauthor)) config_path = path / 'configs' / 'sub_configs' / 'my_super_config.ini' conf = config_path.open(encoding="utf-8") 

    If you really want data from a file located relative to the installed module, use pkgutil.get_data() or setuptools' pkg_resources.resource_string() .

    In this case, there is no particular difference between the os.path functions and the pathlib interface. But in general, there are advantages in using special objects for paths instead of common lines — from PEP 519 :

    If you are not a stitching, you can’t represent a file system path. It can be a path to not.

    As demonstrated by an error at the top of the response, sometimes strings that are not paths ( str(None) ) may accidentally be interpreted as paths, and special objects such as pathlib.Path do not have this flaw.

    Plus, a special object can provide a richer special interface, for example, path.read_text() . Modules exist and exist that use objects to represent paths, for example: path.py

    In practice, if it is possible to use Python 3 or put pathlib on Python 2 , the code that works with the file system is more pleasant to pathlib.Path/os.DirEntry with pathlib.Path/os.DirEntry . Here are some code examples where pathlib makes the code more readable. Here are examples where the same functionality is implemented with and without os.scandir() :

    • By the answer, it turns out that this solves the problem of str(foo) e But why bother to call str at all? open(None) is quite a curse and does not cause problems. - andreymal
    • @andreymal open() expects str / bytes and therefore path-like objects need to be converted to str / bytes. So that ordinary filesystem functions (such as those in importlib) that already work with strings can safely support path-like objects (instead of unsafe str(path) , os.fspath() is called somewhere deep in the guts of functions caused by importlib) that allow them to be more widely used. Using special objects instead of strings for paths can make code more readable, portable, and sometimes more efficient and less prone to errors. - jfs
    • If I do not use path-like objects, then str will not be called, and the rest are empty words) - andreymal
    • @andreymal: you are entitled to your opinion, but you are not entitled to your facts. For example, try writing more readable, efficient and portable code without using os.scandir() or similar path-like objects, for example from the link in the answer . If you can, then your comment is not just an illiterate, unreasonable and unprovoked insult. - jfs
    • Suppose I have not written the code, then it turns out that path-like objects should be used, only because the os.scandir() iterator returns them. And why does it return them, and not (byte) strings? Having run through PEP 471, I did not find the answer (caching is not our case). - andreymal

    This solves the problems that arise when using advanced objects representing file paths with the pathlib module. For example, now it is impossible to use an object of type PurePath to open a file, you need to convert to str ing

     >>> from pathlib import PurePath >>> path = 'workspace' >>> p = PurePath(path) / 'where.txt' >>> with open(p) as f: ... print(f.readline()) ... Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: invalid file: PurePosixPath('workspace/where.txt') >>> with open(str(p)) as f: ... print(f.readline()) ... spam foo, bar, baz 

    __fspath__ resolves this:

    It was a rule of course to introduce a questionnaire through the PEP 428. It is considered. It has been a great deal. You can find out how to find out how to find out how to find the error code.

    This is the path to the object to str (). If you haven’t been able to make it, it’s possible to make a mistake. file.

    • Here and the question begs, why do we need pathlib and PurePath) - andreymal
    • one
      @andreymal: answer is jfs