16

I was expecting Path('') to be a path that does not exist because it does not correspond to a file or directory name. Why is this considered to exist?

from pathlib import Path

print(Path('').exists())

I assume there is an advantage gained by defining the Path('') to be the same as Path('.'). In what case is there an advantage?

dreftymac
  • 31,404
  • 26
  • 119
  • 182
mattm
  • 5,851
  • 11
  • 47
  • 77

3 Answers3

18

As other said, it resolves to the current path and therefore exists, but here's why,

pathlib.Path is acutally a subclass of pathlib.PurePath which assumes the current directory when the pathsegments (argument) is empty (equivalent to '').

You can prove that empirically like this,

from pathlib import PurePath
print(PurePath())
>>>> .

I assume there is an advantage gained by defining the Path('') to be the same as Path('.').

Correct. Even though I'm not the creator of that lib, I assume this is for syntax and logical reasons. Indeed, people often want to refer to the current directory to compute something dynamically. Therefore, for the same reason . points to the current directory, the lib creator probably wanted to let you write something like this,

>>>> p = Path() # or possibly Path('.')
>>> [x for x in p.iterdir() if x.is_dir()]

that would list sub directories.

Basically, see this as a default. It was logic that the default path returned by Path() was the current directory. Thus, logically, an empty string value should have the same behavior.

scharette
  • 9,437
  • 8
  • 33
  • 67
5

If you try stat you get:

$ touch ""
touch: cannot touch '': No such file or directory

but if you peek inside, the story is different:

$ strace -e file touch ""
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=122530, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 ENOENT (No such file or directory)

So you can stat "" because it's the CWD, but you can't open it as a file because no such file exists. Indeed:

$ strace -e file ipython3 
In [1]: import pathlib

In [2]: p = pathlib.Path()

In [3]: p.exists()
newfstatat(AT_FDCWD, ".", {st_mode=S_IFDIR|0755, st_size=20480, ...}, 0) = 0
Out[3]: True

So this is not exactly any kind of assumption from Python's pathlib module, but all the way down the the C lib and kernel.

Marcos Dione
  • 556
  • 6
  • 13
2

Slightly off topic: I want to have a Path whose boolean value is False. Seems to be not possible. I'm doing this inside argparse with type=Path. I suspect that OP wanted something similar.

I ended up using one of two options, neither as "elegant" as it would be if I could simply test "if the_possibly_false_Path:..."

  1. Set the default (which I wish tested False) to something like '%%' which causes argparse to create a Path with the name "%%" which I can then test for
  2. Leave the result as a default type, set the default to something that tests False and then call the Path constructor if the value isn't false.
griswolf
  • 71
  • 1
  • 5
  • Same. But maybe raising an exception is the way to go instead. Personally I'm not fond of raising an exception to perform what is basically an if-else, but ... – Jacob Lee Jul 23 '23 at 00:39