<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>