子类`pathlib.Path`失败

时间:2015-04-24 14:57:28

标签: oop python-3.4

我想增强课程pathlib.Path,但上面的简单示例不起作用。

from pathlib import Path

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

test = PPath("dir", "test.txt")

以下是我的错误消息。

Traceback (most recent call last):
  File "/Users/projetmbc/test.py", line 14, in <module>
    test = PPath("dir", "test.txt")
  File "/anaconda/lib/python3.4/pathlib.py", line 907, in __new__
    self = cls._from_parts(args, init=False)
  File "/anaconda/lib/python3.4/pathlib.py", line 589, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/anaconda/lib/python3.4/pathlib.py", line 582, in _parse_args
    return cls._flavour.parse_parts(parts)
AttributeError: type object 'PPath' has no attribute '_flavour'

我做错了什么?

8 个答案:

答案 0 :(得分:14)

您可以对具体实现进行子类化,因此可以使用:

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

以下是我对此所做的事情:

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("я")

答案 1 :(得分:7)

HerePath类的定义。它做的事情比较聪明。它不是直接从Path返回__new__()的实例,而是返回子类的实例,但只有 才会直接调用Path()(和不作为子类)。

否则,它希望通过WindowsPath()PosixPath()调用,它们都通过多重继承提供_flavour类属性。您还必须在子类化时提供此属性。您可能需要实例化和/或子类化_Flavour类才能执行此操作。这不是API支持的部分,因此您的代码可能会在未来的Python版本中中断。

TL; DR This idea is fraught with peril, and I fear that my answers to your questions will be interpreted as approval rather than reluctant assistance.

答案 2 :(得分:3)

根据您为什么要扩展Path(或PosixPath或WindowsPath),您也许可以简化生活。就我而言,我想实现一个File类,它具有Path的所有方法以及其他一些方法。但是,我实际上并不在乎isinstance(File(),Path)。

委派工作得很漂亮:

class File:

    def __init__(self, path):
        self.path = pathlib.Path(path)
        ...

    def __getattr__(self, attr):
        return getattr(self.path, attr)

    def foobar(self):
        ...

现在,如果file = File('/ a / b / c'),我可以使用文件上的整个Path接口,也可以使用file.foobar()。

答案 3 :(得分:2)

注意

在对Python dev进行一些讨论之后,我打开了a bug track here。列表。

临时解决方案

很抱歉这个双重答案,但这是一种实现我想要的方法。感谢Kevin指出我pathlib的来源以及我们这里有构造函数的事实。

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)

这将打印以下行。

File ? False
Dir  ? False
New name: C:/Users/projetmbc/new.name
Drive ? 
=== === === === 

答案 4 :(得分:1)

我也一直在为此苦苦挣扎。

这是我在pathlib模块中研究的内容。 在我看来,这是一种更清洁的方法,但是如果pathlib模块更改了其实现,则可能会无效。

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")

答案 5 :(得分:0)

这是一个简单的方法来处理凯文的观察。

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

然后我将需要使用一个技巧,以便自动将所有Path的方法绑定到我的PPpath类。我认为这样做很有意思。

答案 6 :(得分:0)

也可以。

double (q[1])(X[2])={(double X[2]){return X[0]}};

打印:

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)

@staticmethod可以替换为@classmethod

答案 7 :(得分:0)

结合之前的一些答案,您也可以只写:

class MyPath(pathlib.Path):
    _flavour = type(pathlib.Path())._flavour