Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I subclass datetime.date?

Tags:

Why doesn't the following work (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) 

I wanted to create a class that was just like datetime.date, but with a different __init__ function. Apparently my function never gets called. Instead the original datetime.date.__init__ is called and fails because that expects 3 arguments and I am passing in one.

What's going on here? And is this a clue?

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

Thanks!

like image 505
Arkady Avatar asked Dec 29 '08 23:12

Arkady


2 Answers

Regarding several other answers, this doesn't have anything to do with dates being implemented in C per se. The __init__ method does nothing because they are immutable objects, therefore the constructor (__new__) should do all the work. You would see the same behavior subclassing int, str, etc.

>>> import datetime >>> class D(datetime.date):         def __new__(cls, year):             return datetime.date.__new__(cls, year, 1, 1)   >>> D(2008) D(2008, 1, 1) 
like image 167
A. Coady Avatar answered Sep 21 '22 06:09

A. Coady


Please read the Python reference on Data model, especially about the __new__ special method.

Excerpt from that page (my italics):

__new__() is intended mainly to allow subclasses of immutable types (like int, str, or tuple) to customize instance creation. It is also commonly overridden in custom metaclasses in order to customize class creation.

datetime.datetime is also an immutable type.

PS If you think that:

  • an object implemented in C cannot be subclassed, or
  • __init__ doesn't get called for C implemented objects, only __new__

then please try it:

>>> 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 >>>  
like image 41
tzot Avatar answered Sep 22 '22 06:09

tzot