<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr">On Sun, 6 Jan 2019 at 11:00, Paul Ganssle <<a href="mailto:paul@ganssle.io">paul@ganssle.io</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div bgcolor="#FFFFFF">
<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).</p></div></blockquote><div><br></div><div>To help set expectations, the current semantics are not a bug and so the proposal isn't fixing a bug but proposing a change in semantics.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div bgcolor="#FFFFFF"><p> 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, </p></div></blockquote><div><br></div><div>We very much do care. Because this isn't a bug but a voluntary semantic change you're proposing to change we can't blindly break people who are relying on the current semantics. We need to have a justification for those people as to why we have decided to change the semantics now after all of these years as well as provide an upgrade path.</div><div><br></div><div>-Brett<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div bgcolor="#FFFFFF"><p>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)</tt> <br></p></div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div bgcolor="#FFFFFF"><p><tt>
<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_8458662023297668833moz-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">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_8458662023297668833gmail-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">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">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">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">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
</blockquote>
</div>
<br>
<br>
-- <br>
<div dir="ltr" class="gmail-m_8458662023297668833gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</blockquote>
</div>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/brett%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/brett%40python.org</a><br>
</blockquote></div></div>