pathlib.Path 的简单子类化出错:没有 _flavour 属性

Ale*_*eft 11 python

我正在尝试从 pathlib 继承 Path,但在实例化时出现以下错误而失败

from pathlib import Path
class Pl(Path):
    def __init__(self, *pathsegments: str):
        super().__init__(*pathsegments)

Run Code Online (Sandbox Code Playgroud)

实例化时出错

AttributeError: type object 'Pl' has no attribute '_flavour'

Run Code Online (Sandbox Code Playgroud)

更新:我继承WindowsPath仍然不起作用。

TypeError: object.__init__() takes exactly one argument (the instance to initialize)

Lev*_* M. 7

Path有点像一个抽象类,实际上根据操作系统实例化为两个可能的子类之一:

PosixPath或者WindowsPath

https://docs.python.org/3/library/pathlib.html

这个基类寻找一个内部(私有)类变量来确定它实际上是什么类型的对象,这个变量被称为_flavour

你有两个选择:

  1. 从具体子类之一派生您的类。
    这是最好的选择,因为它将帮助您处理未记录的库内部结构,并保证您的代码不会在不同版本的库上崩溃。
    如果您希望代码跨平台,则需要根据操作系统以不同的方式定义类。

编辑:根据 dank8 的评论,原始示例代码有一个问题:Path不采用__init__参数,而是__new__采用参数。

此外,还有一种更好的方法可以在运行时确定具体子类。

代码如下所示:

from pathlib import Path

class P1(type(Path())):
    def __new__(cls, *pathsegments):
        return super().__new__(cls, *pathsegments)
Run Code Online (Sandbox Code Playgroud)
  1. 或者自己填写类变量。
    不建议这样做,因为您将使用未记录的元素,这些元素可能会因对库的任何更改而随时中断,但它允许您直接继承Path

请注意,如果您决定使用此方法,可能还会出现其他问题!

import os
from pathlib import _PosixFlavour
from pathlib import _WindowsFlavour

class P1(Path):
    _flavour = _PosixFlavour() if os.name == 'posix' else _WindowsFlavour()

    def __new__(cls, *pathsegments):
        return super().__new__(cls, *pathsegments)
Run Code Online (Sandbox Code Playgroud)

  • 从 Python 3.12 开始,您不需要这样做(定义 `_flavour` 属性) https://docs.python.org/3/whatsnew/3.12.html (2认同)

Ale*_*eft 1

我解决了。Mokey 补丁是必经之路。

像这样定义函数

def method1(self, other):
   blah

Path.method1 = method1

Run Code Online (Sandbox Code Playgroud)

最快、最简单、最方便的解决方案,零缺点。Pycharm 中的自动建议效果很好。

更新:

我得到了解决方案(适用于 linter 和自动建议器):

class MyPath(type(Path()), Path):
    pass

Run Code Online (Sandbox Code Playgroud)