[Python-Dev] Return type of datetime subclasses added to timedelta

Guido van Rossum guido at python.org
Sun Jan 6 13:43:18 EST 2019


I don't think datetime and builtins like int necessarily need to be
aligned. But I do see a problem -- the __new__ and __init__ methods defined
in the subclass (if any) should allow for being called with the same
signature as the base datetime class. Currently you can have a subclass of
datetime whose __new__ has no arguments (or, more realistically, interprets
its arguments differently). Instances of such a class can still be added to
a timedelta. The proposal would cause this to break (since such an addition
has to create a new instance, which calls __new__ and __init__). Since this
is a backwards incompatibility, I don't see how it can be done -- and I
also don't see many use cases, so I think it's not worth pursuing further.

Note that the same problem already happens with the .fromordinal() class
method, though it doesn't happen with .fromdatetime() or .now():

>>> class D(datetime.datetime):
...   def __new__(cls): return cls.now()
...
>>> D()
D(2019, 1, 6, 10, 33, 37, 161606)
>>> D.fromordinal(100)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __new__() takes 1 positional argument but 4 were given
>>> D.fromtimestamp(123456789)
D(1973, 11, 29, 13, 33, 9)
>>>

On Sun, Jan 6, 2019 at 9:05 AM Paul Ganssle <paul at ganssle.io> wrote:

> I can think of many reasons why datetime is different from builtins,
> though to be honest I'm not sure that consistency for its own sake is
> really a strong argument for keeping a counter-intuitive behavior - and to
> be honest I'm open to the idea that *all* arithmetic types *should* have
> some form of this change.
>
> That said, I would say that the biggest difference between datetime and
> builtins (other than the fact that datetime is *not* a builtin, and as
> such doesn't necessarily need to be categorized in this group), is that
> unlike almost all other arithmetic types, *datetime* has a special,
> dedicated type for describing differences in datetimes. Using your example
> of a float subclass, consider that without the behavior of "addition of
> floats returns floats", it would be hard to predict what would happen in
> this situation:
>
> >>> F(1.2) + 3.4
>
> Would that always return a float, even though F(1.2) + F(3.4) returns an
> F? Would that return an F because F is the left-hand operand? Would it
> return a float because float is the right-hand operand? Would you walk the
> MROs and find the lowest type in common between the operands and return
> that? It's not entirely clear which subtype predominates. With datetime,
> you have:
>
> datetime - datetime -> timedelta
> datetime ± timedelta -> datetime
> timedelta ± timedelta -> timedelta
>
> There's no operation between two datetime objects that would return a
> datetime object, so it's always clear: operations between datetime
> subclasses return timedelta, operations between a datetime object and a
> timedelta return the subclass of the datetime that it was added to or
> subtracted from.
>
> Of course, the real way to resolve whether datetime should be different
> from int/float/string/etc is to look at why this choice was actually made
> for those types in the first place, and decide whether datetime is like
> them *in this respect*. The heterogeneous operations problem may be a
> reasonable justification for leaving the other builtins alone but changing
> datetime, but if someone knows of other fundamental reasons why the
> decision to have arithmetic operations always create the base class was
> chosen, please let me know.
>
> Best,
> Paul
> On 1/5/19 3:55 AM, Alexander Belopolsky wrote:
>
>
>
> On Wed, Jan 2, 2019 at 10:18 PM Paul Ganssle <paul at ganssle.io> wrote:
>
>> .. the original objection was that this implementation assumes that the
>> datetime subclass has a constructor with the same (or a sufficiently
>> similar) signature as datetime.
>>
> While this was used as a possible rationale for the way standard types
> behave, the main objection to changing datetime classes is that it will
> make them behave differently from builtins.  For example:
>
> >>> class F(float):
> ...     pass
> ...
> >>> type(F.fromhex('AA'))
> <class '__main__.F'>
> >>> type(F(1) + F(2))
> <class 'float'>
>
> This may be a legitimate gripe, but unfortunately that ship has sailed
>> long ago. All of datetime's alternate constructors make this assumption.
>> Any subclass that does not meet this requirement must have worked around it
>> long ago (or they don't care about alternate constructors).
>>
>
> This is right, but the same argument is equally applicable to int, float,
> etc. subclasses.  If you want to limit your change to datetime types you
> should explain what makes these types special.
>
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/guido%40python.org
>


-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20190106/62f9bcb1/attachment.html>


More information about the Python-Dev mailing list