pythonoverridingsubclasssuperpathlib

How to make method of subclass inherited from pathlib.Path return Path instead of the subclass


Let's say I have defined a subclass inherited from Path, and I want to use methods from Path. For example, Path.glob() here:

from pathlib import Path


class PhotoDir(Path):
    pass

# some custom methods

if __name__ == "__main__":

    path: str = r"Y:\Picture\2023\2023-11-03"
    photoDir: PhotoDir = PhotoDir(path)

    print(list(photoDir.glob("*")))

The result will be:

[
PhotoDir('001.jpg'), 
PhotoDir('002.jpg')
]

All methods from Path will return the subclass PhotoDir.

The result I'm expecting is:

[
Path('001.jpg'), 
Path('002.jpg')
]

And if I defined another subclass of Path Photo, the result should be:

[
Photo('001.jpg'), 
Photo('002.jpg')
]

What I have tried

I have tried override methods with super().glob(), still the same.(It makes no diff if I'm right.):

class PhotoDir(Path):
    def glob(
        self, pattern: str, *, case_sensitive: bool | None = None
    ) -> Generator[Self, None, None]:
        return super().glob(pattern, case_sensitive=case_sensitive)

I also tried Path(self).glob() in the subclass. This one works, but it seems a little bit incorrect to me.(IDK. Maybe it's right. I'm new to Python)

class PhotoDir(Path):
    def glob(
        self, pattern: str, *, case_sensitive: bool | None = None
    ) -> Generator[Self, None, None]:
        return Path(self).glob(pattern, case_sensitive=case_sensitive)

Right now I take a work around:

class PhotoDir:
    def __init__(self, *args: str | PathLike[str]) -> None:
        self.path: Path = Path(*args)

I didn't subclassing Path at all. Instead of using photoDir.glob(), I'm using photoDir.path.glob(). It works fine, but is there a smarter way to do this in Python?


Solution

  • Your PhotoDir class doesn't represent an arbitrary file path, so subclassing isn't appropriate. It represents a directory, one attribute of which is the file path that identifies it, so your final example of composition is the appropriate solution.

    class PhotoDir:
        def __init__(self, *args: str | PathLike[str]) -> None:
            self.path: Path = Path(*args)
    
        def glob(self, *args, **kwargs):
            return self.path.glob(*args, **kwargs)