<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>There's already a PR, actually, #10902: <a
class="gmail-m_8165555785083225151moz-txt-link-freetext"
href="https://github.com/python/cpython/pull/10902"
target="_blank">https://github.com/python/cpython/pull/10902</a><br>
<br>
Victor reviewed and approved it, I think before I started this
thread, so now it's just waiting on merge.<br>
</p>
<div class="moz-cite-prefix">On 2/4/19 11:38 AM, Guido van Rossum
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CAP7+vJLc3N4wHzZxKCmT-C61X9YeTjVh4MT0OdTV7Lt2PbdKQw@mail.gmail.com">
<div dir="ltr">I recommend that you submit a PR so we can get it
into 3.8 alpha 2.<br>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Mon, Feb 4, 2019 at 5:50 AM
Paul Ganssle <<a href="mailto:paul@ganssle.io"
moz-do-not-send="true">paul@ganssle.io</a>> wrote:<br>
</div>
<blockquote class="gmail_quote">
<div>
<p>Hey all,</p>
<p>This thread about the return type of datetime operations
seems to have stopped without any explicit decision - I
think I responded to everyone who had objections, but I
think only Guido has given a +1 to whether or not we
should go ahead.</p>
<p>Have we got agreement to go ahead with this change? Are
we still targeting Python 3.8 here?</p>
<p>For those who don't want to dig through your old e-mails,
here's the archive link for this thread: <a
class="gmail-m_8165555785083225151moz-txt-link-freetext"
href="https://mail.python.org/pipermail/python-dev/2019-January/155984.html"
target="_blank" moz-do-not-send="true">https://mail.python.org/pipermail/python-dev/2019-January/155984.html</a><br>
<br>
If you want to start commenting on the actual
implementation, it's available here (though it's pretty
simple): <a
class="gmail-m_8165555785083225151moz-txt-link-freetext"
href="https://github.com/python/cpython/pull/10902"
target="_blank" moz-do-not-send="true">https://github.com/python/cpython/pull/10902</a><br>
<br>
Best,</p>
<p>Paul</p>
<p><br>
</p>
<div class="gmail-m_8165555785083225151moz-cite-prefix">On
1/6/19 7:17 PM, Guido van Rossum wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">OK, I concede your point (and indeed I only
tested this on 3.6). If we could break the backward
compatibility for now() we presumably can break it for
this purpose.<br>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr">On Sun, Jan 6, 2019 at 11:02 AM Paul
Ganssle <<a href="mailto:paul@ganssle.io"
target="_blank" moz-do-not-send="true">paul@ganssle.io</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote">
<div>
<p>I did address this in the original post - the
assumption that the subclass constructor will have
the same arguments as the base constructor is
baked into many alternate constructors of
datetime. I acknowledge that this is a breaking
change, but it is a small one - anyone creating
such a subclass that <i>cannot</i> handled the
class being created this way would be broken in
myriad ways.<br>
<br>
We have also in recent years changed several
alternate constructors (including `replace`) to
retain the original subclass, which by your same
standard would be a breaking change. I believe
there have been no complaints. In fact, between
Python 3.6 and 3.7, the very example you showed
broke:<br>
<br>
Python 3.6.6:<br>
<br>
>>> class D(datetime.datetime):<br>
... def __new__(cls):<br>
... return cls.now()<br>
... <br>
>>> D()<br>
D(2019, 1, 6, 13, 49, 38, 842033)<br>
<br>
Python 3.7.2:<br>
<br>
>>> class D(datetime.datetime):<br>
... def __new__(cls):<br>
... return cls.now()<br>
... <br>
>>> D()<br>
Traceback (most recent call last):<br>
File "<stdin>", line 1, in <module><br>
File "<stdin>", line 3, in __new__<br>
TypeError: __new__() takes 1 positional argument
but 9 were given</p>
<p><br>
We haven't seen any bug reports about this sort of
thing; what we <i>have</i> been getting is bug
reports that subclassing datetime doesn't retain
the subclass in various ways (because people <i>are</i>
using datetime subclasses). This is likely to
cause very little in the way of problems, but it
will improve convenience for people making
datetime subclasses and almost certainly
performance for people using them (e.g. pendulum
and arrow, which now need to take a slow pure
python route in many situations to work around
this problem).</p>
<p>If we're <i>really</i> concerned with this
backward compatibility breaking, we could do the
equivalent of:<br>
<tt><br>
</tt><tt>try:</tt><tt><br>
</tt><tt> return new_behavior(...)</tt><tt><br>
</tt><tt>except TypeError:</tt><tt><br>
</tt><tt> warnings.warn("The semantics of
timedelta addition have "</tt><tt><br>
</tt><tt> "changed in a way that
raises an error in "<br>
"this subclass. Please
implement __add__ "<br>
"if you need the old
behavior.", DeprecationWarning)<br>
<br>
</tt>Then after a suitable notice period drop the
warning and turn it to a hard error.<br>
</p>
<p>Best,</p>
<p>Paul<br>
</p>
<div
class="gmail-m_8165555785083225151gmail-m_-344422180359162179moz-cite-prefix">On
1/6/19 1:43 PM, Guido van Rossum wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div>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.<br>
</div>
<div><br>
</div>
<div>Note that the same problem already
happens with the .fromordinal() class
method, though it doesn't happen with
.fromdatetime() or .now():</div>
<div><br>
</div>
<div>>>> class
D(datetime.datetime):<br>
... def __new__(cls): return cls.now()<br>
... <br>
>>> D()<br>
D(2019, 1, 6, 10, 33, 37, 161606)<br>
>>> D.fromordinal(100)<br>
Traceback (most recent call last):<br>
File "<stdin>", line 1, in
<module><br>
TypeError: __new__() takes 1 positional
argument but 4 were given<br>
>>> D.fromtimestamp(123456789)<br>
D(1973, 11, 29, 13, 33, 9)<br>
>>> <br>
</div>
</div>
</div>
</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr">On Sun, Jan 6, 2019 at 9:05 AM
Paul Ganssle <<a
href="mailto:paul@ganssle.io"
target="_blank" moz-do-not-send="true">paul@ganssle.io</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote">
<div>
<p>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
<i>all</i> arithmetic types <i>should</i>
have some form of this change.<br>
</p>
<p>That said, I would say that the biggest
difference between datetime and builtins
(other than the fact that datetime is <i>not</i>
a builtin, and as such doesn't necessarily
need to be categorized in this group), is
that unlike almost all other arithmetic
types, <i>datetime</i> 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:<br>
<br>
>>> F(1.2) + 3.4<br>
<br>
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:<br>
<br>
datetime - datetime -> timedelta<br>
datetime ± timedelta -> datetime<br>
timedelta ± timedelta -> timedelta<br>
<br>
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.</p>
<p>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 <i>in this
respect</i>. 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.<br>
<br>
Best,<br>
Paul<br>
</p>
<div
class="gmail-m_8165555785083225151gmail-m_-344422180359162179gmail-m_-6009346472102158879moz-cite-prefix">On
1/5/19 3:55 AM, Alexander Belopolsky
wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr">
<div dir="ltr"><br>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr">On Wed, Jan 2, 2019
at 10:18 PM Paul Ganssle <<a
href="mailto:paul@ganssle.io"
target="_blank"
moz-do-not-send="true">paul@ganssle.io</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote">
<div>
<p>.. 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.</p>
</div>
</blockquote>
<div>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:</div>
<div>
<div><br>
</div>
<div>>>> class
F(float):</div>
<div>... pass</div>
<div>...</div>
</div>
<div>
<div>>>>
type(F.fromhex('AA'))</div>
<div><class '__main__.F'></div>
<div>>>> type(F(1) +
F(2))</div>
<div><class 'float'></div>
</div>
<div><br>
</div>
<blockquote class="gmail_quote">
<div>
<p> 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).</p>
</div>
</blockquote>
<div><br>
</div>
<div>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. </div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org"
target="_blank" moz-do-not-send="true">Python-Dev@python.org</a><br>
<a
href="https://mail.python.org/mailman/listinfo/python-dev"
rel="noreferrer" target="_blank"
moz-do-not-send="true">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a
href="https://mail.python.org/mailman/options/python-dev/guido%40python.org"
rel="noreferrer" target="_blank"
moz-do-not-send="true">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
</blockquote>
</div>
<br>
<br>
-- <br>
<div dir="ltr"
class="gmail-m_8165555785083225151gmail-m_-344422180359162179gmail_signature">--Guido
van Rossum (<a href="http://python.org/~guido"
target="_blank" moz-do-not-send="true">python.org/~guido</a>)</div>
</blockquote>
</div>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank"
moz-do-not-send="true">Python-Dev@python.org</a><br>
<a
href="https://mail.python.org/mailman/listinfo/python-dev"
rel="noreferrer" target="_blank"
moz-do-not-send="true">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a
href="https://mail.python.org/mailman/options/python-dev/guido%40python.org"
rel="noreferrer" target="_blank"
moz-do-not-send="true">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
</blockquote>
</div>
<br>
<br>
-- <br>
<div dir="ltr"
class="gmail-m_8165555785083225151gmail_signature">--Guido
van Rossum (<a href="http://python.org/~guido"
target="_blank" moz-do-not-send="true">python.org/~guido</a>)</div>
</blockquote>
</div>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank"
moz-do-not-send="true">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev"
rel="noreferrer" target="_blank" moz-do-not-send="true">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a
href="https://mail.python.org/mailman/options/python-dev/guido%40python.org"
rel="noreferrer" target="_blank" moz-do-not-send="true">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
</blockquote>
</div>
<br>
<br>
-- <br>
<div dir="ltr" class="gmail_signature">--Guido van Rossum (<a
href="http://python.org/~guido" target="_blank"
moz-do-not-send="true">python.org/~guido</a>)</div>
</blockquote>
</body>
</html>