If you use __new__
, instead of __init__
:
import datetime as DT
class Hours(DT.timedelta):
def __new__(self, hours):
return DT.timedelta.__new__(self, hours=hours)
x = Hours(10)
print(x)
yields
10:00:00
If you override __init__
, but not __new__
, then DT.timedelta.__new__
gets called before your Hours.__init__
. Notice
import datetime as DT
class Hours(DT.timedelta):
def __init__(self, hours):
print(self)
x = Hours(10)
prints 10 days, 0:00:00
. This shows that DT.timedelta.__new__
has already set the timedelta to 10 days before you even get a chance to configure it in Hours.__init__
.
Moreover, DT.timedelta
is an immutable object -- you can't change the days
or seconds
or microseconds
after the object has been instantiated. Python creates immutable objects by using the __new__
method, and generally don't do anything in the __init__
method. Mutable objects do the reverse: they configure the object in __init__
and don't do anything in __new__
.
Per the docs:
When subclassing immutable built-in types like numbers and strings,
and occasionally in other situations, the static method __new__
comes
in handy. __new__
is the first step in instance construction, invoked
before __init__
. The __new__
method is called with the class as its
first argument; its responsibility is to return a new instance of that
class. Compare this to __init__
: __init__
is called with an instance
as its first argument, and it doesn't return anything; its
responsibility is to initialize the instance....
All this is done so that immutable types can preserve their
immutability while allowing subclassing.
(If immutable objects performed configuration in __init__
, then you could mutate an immutable by calling immutable.__init__
. Obviously, we don't want that, so immutable.__init__
generally does nothing.)
Note also that unless you plan to add new methods to your Hours
class, it would be simpler, and therefore better to just use a function:
def hours(hours):
return DT.timedelta(hours=hours)