如何子类化具有__new__的类并依赖于cls的值?

时间:2015-06-18 19:22:15

标签: python

我的具体用例是我试图继承pathlib.Path。我希望能够添加或覆盖某些功能,但我还想继承所有Path。路径有__new__,其中包含:

if cls is Path:
    cls = WindowsPath if os.name == 'nt' else PosixPath

换句话说,Path需要将适当的类传递给它。问题是我不知道如何创建MY课程并使用Path.__new__致电cls == Path

我尝试了很多东西,每个人都给了我一个不同的问题。 这个给了我AttributeError: type object 'RPath' has no attribute '_flavour',因为我试图覆盖父类。

Python3:

class RPath(Path):
    def __new__(cls, basedir, *args, **kwargs):
         return Path.__new__(cls, *args, **kwargs)

    def __init__(self, basedir, *pathsegs):
        super().__init__()
        self.basedir = basedir

    def newfunction(self):
        print('Something new')

这个返回一个Path对象,因此不允许我进行覆盖。

def __new__(cls, basedir, *args, **kwargs):
    return Path.__new__(Path, *args, **kwargs)

我也尝试了super()的各种用法,但没有用。

这似乎应该很容易。我错过了什么?

更新:我想要完成什么? 具体来说,我想制作class RPath(basedir, *pathsegments)

rpath=RPath('\root\dir', 'relpath\path2\file.ext)
assert rpath.basedir == '\root\dir' # True
rpath.rebase('\new_basedir')
assert rpath.basedir === '\newbasedir' # True
# And while I'm at it
assert rpath.str == str(rpath)  # make str a property == __str__(self)

3 个答案:

答案 0 :(得分:2)

我不认为这会以通常的方式实现。但即使你能做到这一点,它也行不通,因为Path正在做的事情也不是返回一个普通的Path,而是返回一些子类(WindowsPath或PosixPath)。所以你对Path的覆盖不会生效,因为如果你能够继承Path.__new__,它仍然会返回一个WindowsPath,而WindowsPath继承自Path,而不是你的自定义路径子类。

似乎pathlib.Path有一个特殊的类结构,你必须做一些特殊的工作来复制它。首先,您需要创建自己的WindowsPath和PosixPath子类,然后创建一个Path子类,该子类委托实例化其中一个而不是自身。

答案 1 :(得分:1)

这是 a 解决方案,但它不使用继承。我仍然怀疑有一种直接的,简单的继承方式(虽然看到BrenBarn对另一方的回应)。

此方法使用合成。关键是使用__getattr__getattr()自动将包装类中未找到的所有请求委托给包装类。这是一个例子:

class RPath(object):
    def __init__(self, basedir, *pathsegs):
        self.p = Path(*pathsegs)
        self.basedir = basedir

    # Override existing behavior
    def __eq__(self, other):
        return type(other) is RPath and self.basedir == other.basedir and self.p == other.p      

    # Add new behavior
    def cp(self):
        return self.basedir / self.p      

    # Everything not found here, automatically delegate to Path
    def __getattr__(self, attr):
        return getattr(self.cp, attr)

答案 2 :(得分:0)

Remember that you are under absolutely no obligation to actually call your superclass's __new__ or __init__. The only constraint is that you ultimately call object.__new__(cls) in order to allocate an object of type cls. So, simply copy the relevant logic out of your superclass's __new__ into your own.