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 > <mailto: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 >> <mailto: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 >>> <mailto: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 <mailto: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 <mailto: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 >>> <http://python.org/~guido>) >> _______________________________________________ >> Python-Dev mailing list >> Python-Dev@python.org <mailto: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 <http://python.org/~guido>) > _______________________________________________ > Python-Dev mailing list > Python-Dev@python.org <mailto: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 <http://python.org/~guido>)
signature.asc
Description: OpenPGP digital signature
_______________________________________________ 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