Issue 36334: pathlib.Path unexpected (wrong) behaviour when combining paths in a for loop (original) (raw)
I wish to create a list of pathlib.Paths by combining two lists of pathlib.Paths. I use two for loops to make every combination.
However the output is not what one would expect (see no 'Program Files' is visible in the output).
########## INPUT:
pa = [
Path('C:/Program Files'),
Path('C:/')
]
pb = [
Path('/one/two/three.exe'),
Path('/four.exe')
]
print( [a/b for a in pa for b in pb] )
########### OUTPUT: [WindowsPath('C:/one/two/three.exe'), WindowsPath('C:/four.exe'), WindowsPath('C:/one/two/three.exe'), WindowsPath('C:/four.exe')]
This is true whether I use for loops or list comprehensions.
To get the expected output I need to change the Paths to strings, combine them, then convert them back to paths like this:
########### INPUT: print( [Path(str(a)+str(b)) for a in pa for b in pb] ) ########### OUTPUT: [WindowsPath('C:/Program Files/one/two/three.exe'), WindowsPath('C:/Program Files/four.exe'), WindowsPath('C:/one/two/three.exe'), WindowsPath('C:/four.exe')]
Interestingly if I print only 'a' I get the expected answer: ########### INPUT: print( [a for a in pa for b in pb] ) ########### OUTPUT: [WindowsPath('C:/Program Files'), WindowsPath('C:/Program Files'), WindowsPath('C:/'), WindowsPath('C:/')]
And the same is true if I print only 'b': ########### INPUT: print( [b for a in pa for b in pb] ) ########### OUTPUT: [WindowsPath('/one/two/three.exe'), WindowsPath('/four.exe'), WindowsPath('/one/two/three.exe'), WindowsPath('/four.exe')]
Additionally in some cases it does give the correct answer. Here is a similar example where the answer is correct: ########### INPUT: pa = [Path('C:/'), Path('D:/')] pb = [Path('a.exe'), Path('b.exe')] print( [a/b for a in pa for b in pb] ) ########### OUTPUT: [WindowsPath('C:/a.exe'), WindowsPath('C:/b.exe'), WindowsPath('D:/a.exe'), WindowsPath('D:/b.exe')]
The drive is retained when a rooted path is joined to a drive-absolute or UNC-absolute path. This is documented behavior 1:
When several absolute paths are given, the last is taken as an
anchor (mimicking os.path.join()’s behaviour):
>>> PurePath('/etc', '/usr', 'lib64')
PurePosixPath('/usr/lib64')
>>> PureWindowsPath('c:/Windows', 'd:bar')
PureWindowsPath('d:bar')
However, in a Windows path, changing the local root doesn’t
discard the previous drive setting:
>>> PureWindowsPath('c:/Windows', '/Program Files')
PureWindowsPath('c:/Program Files')
If you want to simply append directories to a path, use a relative path. For example:
>>> Path('C:/Program Files') / Path('one/two/three.exe')
WindowsPath('C:/Program Files/one/two/three.exe')