Python 子类超级返回self应该返回子类

Python 子类超级返回self应该返回子类,python,python-2.7,python-3.x,Python,Python 2.7,Python 3.x,我正在尝试扩展datetime.date类允许添加ints,而不是使用timedelta对象: class Date(datetime.date): def __add__(self, other): if isinstance(other, int): other = datetime.timedelta(days=other) return super(Date, self).__add__(other) 问题是上面的\uu

我正在尝试扩展
datetime.date
类允许添加
int
s,而不是使用
timedelta
对象:

class Date(datetime.date):
    def __add__(self, other):
        if isinstance(other, int):
            other = datetime.timedelta(days=other)
        return super(Date, self).__add__(other)
问题是上面的
\uu add\uu()
方法将返回
datetime.date
的实例,而不是
date

根据我的理解,没有办法让
super()。\uuuu add\uuuu()
知道
Date
类型。最优雅的解决方案是从
datetime.date
复制整个
\uuuu add\uuu()
方法,并添加额外的代码位。是否有方法将
datetime.date
对象强制转换为
date
方法中的
date
对象

下面是一个突出问题的片段:

D = Date(2000,1,1)
d = D + 1
type(d) # datetime.date instead of Date
编辑:查看(搜索“上课日期”)后,我的第一个解决方案是:

class Date(datetime.date):
    def __add__(self, other):
        if isinstance(other, int):
            other = datetime.timedelta(days=other)
        d = super(Date, self).__add__(other)
        self.__year = d.year
        self.__month = d.month
        self.__day = d.day
        return self # this is of type datetime.date
好的,我想我应该指出我的第一次尝试是:

class Date(datetime.date):
    def __add__(self, other):
        if isinstance(other, int):
            other = datetime.timedelta(days=other)
        d = super(Date, self).__add__(other)
        d.__class__ = Date
        return d
这将不起作用,因为(正如我所怀疑的)datetime模块是用C编写的,并且根据这些类型,您不能将其分配给
\uuuuuu class\uuuu
。我有点困惑datetime.py中的代码是什么

问题是上面的add()方法将返回datetime.date的实例,而不是日期

它会的,但这就是为什么您要使用super(),毕竟:您确实想要调用super类的方法

您可以调用自己类的复制构造函数

最优雅的解决方案是从datetime.date复制整个add()方法,并添加额外的代码


我认为这不是一个很好的解决方案。另外,我认为datetime模块是C。

添加后,只需从
datetime.Date
创建另一个
Date
对象,并按如下方式返回它

    def __add__(self, other):
        if isinstance(other, int):
            other = datetime.timedelta(days=other)
        result = super(Date, self).__add__(other)
        return Date(result.year, result.month, result.day)
这是一个测试

D = Date(2000, 1, 1) + 1
print(type(D), D)
# (<class '__main__.Date'>, Date(2000, 1, 2))
D=日期(2000,1,1)+1
打印(类型(D),D)
#(,日期(2000年1月2日))
一般来说,
super(Subclass,self)。\uu添加(other)
可以返回
Subclass
实例:

class Base(object):
    __slots__ = 'n'
    def __new__(cls, n):
        self = object.__new__(cls)
        self.n = n
        return self
    @classmethod
    def fromordinal(cls, n):
        return cls(n)
    def __add__(self, other):
        if hasattr(other, 'n'):
            return self.fromordinal(self.n + other.n)
        return NotImplemented
    def __repr__(self):
        return "{cls}({arg})".format(cls=self.__class__.__name__, arg=self.n)
    def __eq__(self, other):
        return self.n == other.n

class Subclass(Base):
    __slots__ = ['_secret']
    def __add__(self, other):
        if hasattr(other, '_secret'):
            other = self.fromordinal(other._secret)
        return super(Subclass, self).__add__(other)


a = Subclass(1)
b = Subclass(2)
c = Subclass(2)
c._secret = 3
print(a + b)
print(a + c)
assert (a + b) == Subclass(3)
assert (a + c) == Subclass(4)
assert b == c and (a + b) != (a + c) and type(a + b) == type(a + c) == Subclass

但是,
datetime.date.\uu添加
方法被硬编码为返回
datetime.date
实例,即使对于
datetime.date
子类也是如此。出于性能原因,不从子类调用(可能)纯Python
\uuuuuuuuuuuuuuuuuuuuuuuuuuu
方法。其他Python实现(如Pypy、IronPython、Jython)可能使用的纯Python
datetime.py
,不调用子类方法以与CPython兼容。

类似于
返回日期(super(Date,self)的东西怎么样不幸的是,
?@bimsapi不起作用。似乎
datetime.date
的构造函数不是那么好。当然
super
方法返回一个
datetime.date
,这是超类!你可以从中创建一个
date
d=super(date,self)。\uu添加(other);返回日期(d.year,d.month,d.day)
。是的,它是C。有一个
datetime.py
,但是所有的方法都是空的,并且不返回任何值。好的,我认为是C可以解释为什么我不能只覆盖self。uuu class\uuu=Date in Date。uuu在返回对象之前添加。\uu()第一个更改似乎不需要。@matsjoyce哦,是的。这是不必要的。谢谢:)是的,工作-这是我上面第一次编辑的优雅版本:)@s5s实际上,您的编辑使
+
成为一个可变操作,这是不推荐的。那么datetime.py文件做什么呢?这仅仅是围绕C代码的python包装吗?@s5s:请参阅python发行版7989::stdlib的长期目标是将C扩展模块最小化,使其仅限于那些必须用C编写的模块(模块仍然可以具有增强性能的扩展后端)。由于datetime不满足这一要求,因此datetime将获得纯Python版本,并且仅为提高性能而使用扩展代码,这不是“如果”的问题,而是“何时”的问题。。。要记住的关键是,这是为了使除CPython之外的vm不被视为二级。