I'll merge it tonight. On Mon, Feb 4, 2019 at 2:22 PM Guido van Rossum <gu...@python.org> wrote:
> OK, I approved the PR. Can some other core dev ensure that it gets merged? > No backports though! > > On Mon, Feb 4, 2019 at 8:46 AM Paul Ganssle <p...@ganssle.io> wrote: > >> There's already a PR, actually, #10902: >> https://github.com/python/cpython/pull/10902 >> >> Victor reviewed and approved it, I think before I started this thread, so >> now it's just waiting on merge. >> On 2/4/19 11:38 AM, Guido van Rossum wrote: >> >> I recommend that you submit a PR so we can get it into 3.8 alpha 2. >> >> On Mon, Feb 4, 2019 at 5:50 AM Paul Ganssle <p...@ganssle.io> wrote: >> >>> Hey all, >>> >>> 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. >>> >>> Have we got agreement to go ahead with this change? Are we still >>> targeting Python 3.8 here? >>> >>> For those who don't want to dig through your old e-mails, here's the >>> archive link for this thread: >>> https://mail.python.org/pipermail/python-dev/2019-January/155984.html >>> >>> If you want to start commenting on the actual implementation, it's >>> available here (though it's pretty simple): >>> https://github.com/python/cpython/pull/10902 >>> >>> Best, >>> >>> Paul >>> >>> >>> On 1/6/19 7:17 PM, Guido van Rossum wrote: >>> >>> 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. >>> >>> On Sun, Jan 6, 2019 at 11:02 AM Paul Ganssle <p...@ganssle.io> wrote: >>> >>>> 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 *cannot* handled the class being created this way would >>>> be broken in myriad ways. >>>> >>>> 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: >>>> >>>> Python 3.6.6: >>>> >>>> >>> class D(datetime.datetime): >>>> ... def __new__(cls): >>>> ... return cls.now() >>>> ... >>>> >>> D() >>>> D(2019, 1, 6, 13, 49, 38, 842033) >>>> >>>> Python 3.7.2: >>>> >>>> >>> class D(datetime.datetime): >>>> ... def __new__(cls): >>>> ... return cls.now() >>>> ... >>>> >>> D() >>>> Traceback (most recent call last): >>>> File "<stdin>", line 1, in <module> >>>> File "<stdin>", line 3, in __new__ >>>> TypeError: __new__() takes 1 positional argument but 9 were given >>>> >>>> >>>> We haven't seen any bug reports about this sort of thing; what we >>>> *have* been getting is bug reports that subclassing datetime doesn't >>>> retain the subclass in various ways (because people *are* 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). >>>> >>>> If we're *really* concerned with this backward compatibility breaking, >>>> we could do the equivalent of: >>>> >>>> try: >>>> return new_behavior(...) >>>> except TypeError: >>>> warnings.warn("The semantics of timedelta addition have " >>>> "changed in a way that raises an error in " >>>> "this subclass. Please implement __add__ " >>>> "if you need the old behavior.", DeprecationWarning) >>>> >>>> Then after a suitable notice period drop the warning and turn it to a >>>> hard error. >>>> >>>> Best, >>>> >>>> Paul >>>> On 1/6/19 1:43 PM, Guido van Rossum wrote: >>>> >>>> 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 <p...@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 <p...@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@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) >>>> >>>> _______________________________________________ >>>> Python-Dev mailing list >>>> Python-Dev@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) >>> >>> _______________________________________________ >>> Python-Dev mailing list >>> Python-Dev@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) >> >> _______________________________________________ >> Python-Dev mailing list >> Python-Dev@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) > _______________________________________________ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/alexander.belopolsky%40gmail.com >
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com