Subclass `pathlib.Path` fails

后端 未结 7 1609
情歌与酒
情歌与酒 2020-12-16 10:24

I would like to enhance the class pathlib.Path but the simple example above dose not work.

from pathlib import Path

class PPath(Path):
    def          


        
相关标签:
7条回答
  • 2020-12-16 10:31

    You can subclass the concrete implementation, so this works:

    class Path(type(pathlib.Path())):
    

    Here's what I did with this:

    import pathlib
    
    class Path(type(pathlib.Path())):
        def open(self, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
            if encoding is None and 'b' not in mode:
                encoding = 'utf-8'
            return super().open(mode, buffering, encoding, errors, newline)
    
    Path('/tmp/a.txt').write_text("я")
    
    0 讨论(0)
  • 2020-12-16 10:32

    I have been struggling with this too.

    Here is what i did, studying from the pathlib module. Seems to me that is the cleaner way to do it, but if the pathlib module changes its implementation, it probably won't hold.

    from pathlib import Path
    import os
    import pathlib
    
    class PPath(Path):
    
        _flavour = pathlib._windows_flavour if os.name == 'nt' else pathlib._posix_flavour
    
        def __new__(cls, *args):
            return super(PPath, cls).__new__(cls, *args)
    
        def __init__(self, *args):
            super().__init__() #Path.__init__ does not take any arg (all is done in new)
            self._some_instance_ppath_value = self.exists() #Path method
    
        def some_ppath_method(self, *args):
            pass
    
    test = PPath("dir", "test.txt")
    
    0 讨论(0)
  • 2020-12-16 10:34

    It's work too.

    from pathlib import Path
    
    class SystemConfigPath(type(Path())):
        def __new__(cls, **kwargs):
            path = cls._std_etc()
            return super().__new__(cls, path, **kwargs)
    
        @staticmethod
        def _std_etc():
            return '/etc'
    
    name = SystemConfigPath()
    name = name / 'apt'
    print(name)
    

    Printed:

    /etc/apt
    

    @staticmethod can be replaced by @classmethod

    0 讨论(0)
  • 2020-12-16 10:35

    You may be able to simplify your life depending on why you want to extend Path (or PosixPath, or WindowsPath). In my case, I wanted to implement a File class that had all the methods of Path, and a few others. However, I didn't actually care if isinstance(File(), Path).

    Delegation works beautifully:

    class File:
    
        def __init__(self, path):
            self.path = pathlib.Path(path)
            ...
    
        def __getattr__(self, attr):
            return getattr(self.path, attr)
    
        def foobar(self):
            ...
    

    Now, if file = File('/a/b/c'), I can use the entire Path interface on file, and also do file.foobar().

    0 讨论(0)
  • 2020-12-16 10:36

    Note

    I have opened a bug track here after a little discussion on the Python dev. list.

    A temporary solution

    Sorry for this double answer but here is a way to achieve what I want. Thanks to Kevin that points me to the source of pathlib and the fact we have here constructors.

    import pathlib
    import os
    
    def _extramethod(cls, n):
        print("=== "*n)
    
    class PathPlus(pathlib.Path):
        def __new__(cls, *args):
            if cls is PathPlus:
                cls = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath
    
            setattr(cls, "extramethod", _extramethod)
    
            return cls._from_parts(args)
    
    test = PathPlus("C:", "Users", "projetmbc", "onefile.ext")
    
    print("File ?", test.is_file())
    print("Dir  ?", test.is_dir())
    print("New name:", test.with_name("new.name"))
    print("Drive ?", test.drive)
    
    test.extramethod(4)
    

    This prints the following lines.

    File ? False
    Dir  ? False
    New name: C:/Users/projetmbc/new.name
    Drive ? 
    === === === === 
    
    0 讨论(0)
  • 2020-12-16 10:41

    Here is a simple way to do things regarding to the observation made by Kevin.

    class PPath():
        def __init__(self, *args, **kwargs):
            self.path = Path(*args, **kwargs)
    

    Then I will need to use a trick so as to automatically bind all the Path's methods to my PPpath class. I think that will be funny to do.

    0 讨论(0)
提交回复
热议问题