Почему я не могу подклассифицировать datetime.date?

Почему не выполняется следующая работа (Python 2.5.2)?

>>> import datetime
>>> class D(datetime.date):
        def __init__(self, year):
            datetime.date.__init__(self, year, 1, 1)
>>> D(2008)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: function takes exactly 3 arguments (1 given)

Я хотел создать класс, который был как datetime.date, но с другой функцией __init__. По-видимому, моя функция никогда не называется. Вместо этого оригинал datetime.date.__init__ вызывается и терпит неудачу, потому что он ожидает 3 аргумента, и я передаю один.

Что здесь происходит? И это подсказка?

>>> datetime.date.__init__
<slot wrapper '__init__' of 'object' objects>

Спасибо!

Ответ 1

Что касается нескольких других ответов, это не имеет ничего общего с датами, внедряемыми в C per se. Метод __init__ ничего не делает, поскольку они являются неизменяемыми объектами, поэтому конструктор (__new__) должен выполнять всю работу. Вы увидите одно и то же поведение подкласса int, str и т.д.

>>> import datetime
>>> class D(datetime.date):
        def __new__(cls, year):
            return datetime.date.__new__(cls, year, 1, 1)


>>> D(2008)
D(2008, 1, 1)

Ответ 2

Пожалуйста, прочитайте ссылку Python на Модель данных, особенно о __new__ специальный метод.

Выдержка из этой страницы (курсив мой):

__new__() предназначен главным образом для того, чтобы позволить подклассам неизменяемых типов (например, int, str или кортеж) настраивать создание экземпляра. Он также обычно переопределяется в пользовательских метаклассах, чтобы настроить создание классов.

datetime.datetime также является неизменным типом.

PS Если вы думаете, что:

  • объект, реализованный в C, не может быть подклассифицирован или
  • __init__ не вызывается для объектов C, только __new__

затем попробуйте:

>>> import array
>>> array
<module 'array' (built-in)>
>>> class A(array.array):
    def __init__(self, *args):
        super(array.array, self).__init__(*args)
        print "init is fine for objects implemented in C"

>>> a=A('c')
init is fine for objects implemented in C
>>> 

Ответ 4

Функция вы не обходитесь; Python просто никогда не доходит до точки, где он будет ее называть. Поскольку datetime реализуется в C, он выполняет свою инициализацию в datetime.__new__ not datetime.__init__. Это связано с тем, что datetime является неизменным. Вероятно, вы можете обойти это, переопределив __new__ вместо __init__. Но, как предложили другие люди, лучший способ - это, вероятно, вообще не подклассы datetime.

Ответ 5

Вероятно, вы должны использовать функцию factory вместо создания подкласса:

def first_day_of_the_year(year):
  return datetime.date(year, 1, 1)

Ответ 6

Вы можете обернуть его и добавить расширенную функциональность в свою упаковку.

Вот пример:

class D2(object):
    def __init__(self, *args, **kwargs):
        self.date_object = datetime.date(*args, **kwargs)

    def __getattr__(self, name):
        return getattr(self.date_object, name)

И вот как это работает:

>>> d = D2(2005, 10, 20)
>>> d.weekday()
3
>>> dir(d)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattr__',
 '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
 '__weakref__', 'date_object']
>>> d.strftime('%d.%m.%Y')
'20.10.2005'
>>>

Обратите внимание, что dir() не перечисляет атрибуты datetime.date.