2015-01-11 3 views
2

Я пытаюсь расширить класс datetime.date допускает добавление int сек вместо того чтобы работать с timedelta объектами:Подкласс супер возвращение самостоятельно должен возвращать подкласс

class Date(datetime.date): 
    def __add__(self, other): 
     if isinstance(other, int): 
      other = datetime.timedelta(days=other) 
     return super(Date, self).__add__(other) 

Проблема заключается в том, что метод __add__() выше будет возвращать экземпляр от datetime.date вместо Date.

От моего понимания, нет способа сделать super().__add__() осведомленным о Date типа. Самое элегантное решение - скопировать весь метод __add__() с datetime.date и добавить дополнительный бит кода. Есть ли способ сделать объект datetime.date объекту Date в методе Date.__add__()?

Вот отрывок, чтобы выделить вопрос:

D = Date(2000,1,1) 
d = D + 1 
type(d) # datetime.date instead of Date 

EDIT: Мой первый раствор после глядя на datetime.py (поиск "даты класса"), чтобы сделать это:

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 

OK , Я подумал, что хотел бы указать, что моя первая попытка:

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 

, который не будет работать k, поскольку (как я подозревал) модуль datetime находится в C и в соответствии с this post для таких типов вы не можете назначить __class__. Я немного смущен, что код в datetime.py для этого.

+0

Что-то вроде 'return Date (super (Date, self) .__ add __ (other)'? – bimsapi

+0

@bimsapi Не работает, к сожалению. Кажется, что конструктор 'datetime.date' не так хорош – matsjoyce

+0

Конечно, методы 'super' возвращают' datetime.date', ** это суперкласс **! Однако вы можете создать 'Date' из него:' d = super (Date, self) .__ add __ (other) , return Date (d.year, d.month, d.day) '. – jonrsharpe

ответ

2

После добавления, просто создать еще один объект Date из datetime.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)) 
+0

Первое изменение не представляется необходимым – matsjoyce

+0

@matsjoyce О да, это не обязательно.) – thefourtheye

+0

Да, работает - это изящная версия моего первого Редактировать выше :) – s5s

0

Проблема в том, что метод add() выше вернет экземпляр datetime.date вместо даты.

Это будет, но именно поэтому вы используете super(), в конце концов: вы действительно хотите вызвать метод суперклассов.

Вы можете просто вызвать конструктор своего собственного класса!

Самое элегантное решение состоит в том, чтобы скопировать весь метод add() из datetime.date и добавить дополнительный бит кода.

Это, на мой взгляд, нельзя назвать элегантным решением. Кроме того, я думаю, что модуль DateTime является C.

+0

Yup, это C. Существует' datetime.py', но все методы пустые и возвращают None. – matsjoyce

+0

Хорошо, я думал, что это C, который объяснит, почему я не могу просто перезаписать себя .__ class__ = Дата в Date .__ добавить __() перед возвратом объекта. – s5s

0

В общий, super(Subclass, self).__add__(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.__add__ метод жестко запрограммирован на возврат datetime.date экземпляров даже для datetime.date подклассов.In CPython, it is implemented in C, что по соображениям производительности не вызывает (возможно) чистый метод Python __add__ из подкласса. Pure Python datetime.py, который может использоваться другими реализациями Python, такими как Pypy, IronPython, Jython, не вызывает методы подкласса для совместимости с CPython.

+0

Так что же делает файл datetime.py? Это просто оболочки python вокруг кода C? – s5s

+0

@ s5s: см. Python issue7989: [Добавить чистую реализацию модуля datetime для Python в CPython] (http://bugs.python.org/issue7989): * Указанная долгосрочная цель stdlib заключается в минимизации модулей расширения C только для тех, которые должны быть записаны на C (модули могут по-прежнему иметь улучшающие производительность расширения). Поскольку datetime не соответствует этому требованию, это не вопрос «если», а «когда» datetime получит чистую версию Python и использует код расширения только для производительности. * ... * Главное, чтобы помнить, что это так ВМ, отличные от CPython, не рассматриваются как второстепенные. * – jfs

Смежные вопросы