This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: pathlib.Path unexpected (wrong) behaviour when combining paths in a for loop
Type: behavior Stage: resolved
Components: Windows Versions: Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Mike Davies, eryksun, paul.moore, steve.dower, tim.golden, zach.ware
Priority: normal Keywords:

Created on 2019-03-18 02:12 by Mike Davies, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (2)
msg338156 - (view) Author: Mike Davies (Mike Davies) Date: 2019-03-18 02:12
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')]
msg338160 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2019-03-18 04:08
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')

[1]: https://docs.python.org/3/library/pathlib.html#pathlib.PurePath
History
Date User Action Args
2022-04-11 14:59:12adminsetgithub: 80515
2019-03-18 04:08:02eryksunsetstatus: open -> closed

nosy: + eryksun
messages: + msg338160

resolution: not a bug
stage: resolved
2019-03-18 02:12:20Mike Daviescreate