Author abarnert
Recipients abarnert, gvanrossum, martin.panter, ncoghlan, r.david.murray, serhiy.storchaka
Date 2016-01-05.07:33:16
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1451979198.22.0.84826645528.issue25958@psf.upfronthosting.co.za>
In-reply-to
Content
> A Mercurial export patch should work with the Reitveld review thing if it is a single revision (and based on a public revision).

Well, it's 7 separate commits on a work branch, so I could check in each piece and test it separately, and then I just compared the branch to its parent (default) for the export. But, as I said, I can flatten it into a single diff if the review system can't handle this way.

Sorry for making the first patch hard to review, and thanks for reviewing it anyway; I'll fix that with the next one.

> You have a stray print() call, probably in Hashable.__subclasshook__().

Thanks; fixed for the next patch.

> For a the do-nothing __reversed__() implementation, do you think “yield from ()” would be clearer than “while False”? Or even “return iter(())”?

Maybe, but this way is identical to the definition for the do-nothing Iterable.__iter__.

> What’s the advantage of having Reversed inherit Iterable?

This was discussed briefly... somewhere, maybe the -ideas thread? 

Pro: If they were independent types, more people would probably register with/inherit from Reversible but not Iterable in error than intentionally.

Pro: One less thing for Sequence to inherit from. This was mentioned in the context of adding both Reversible and HalfSequence (or whatever it ends up being called): "class Sequence(Iterable, Reversible, HalfSequence, Sized, Container) seems a little much; "class Sequence(Reversible, HalfSequence, Sized, Container)" is slightly better.

Con: It's not completely impossible that a type could be reversible but not iterable. For example, you might have a reversible, and even indexable-with-negative-indicies-only, infinite collection of all the negative numbers. (But nobody could think of an actual _useful_ example of such a type.)

Those are all pretty trivial points. When Guido said someone needs to work out where Reversible fits into the hierarchy, and there'd been enough talk without a patch. So I looked at where the discussion seemed to be leaning, couldn't find any additional problems with it when I looked into it further, and did it that way. Guido said he liked it on the Reversible bug, so I did it the same way here.

So, no strong arguments or even feelings from anyone; if you've got one, definitely chime in.

> How does the subclass hook interact with classes that implement __reversed__() but not __iter__()? I don’t see how the self.assertFalse(issubclass(K, Reversible)) test could pass.

Exactly the same way Iterator's handles a class that defines __next__ but not __iter__.

I'll double-check that it actually is implemented right before the next patch (and verify that the tests run), but it should be "return _check_methods(C, "__reversed__", "__iter__").

> Should the new Reversed class be excluded from collections.__all__, or is it not worth it?

It's Reversible, not Reversed. It's in __all__, and I'm pretty sure it should be there--if it's not worth exporting, it's not worth creating in the first place, or documenting, right?

> I find the lambda generator a bit quirky in test_Reversible(). Maybe it would be better as an ordinary non-lambda generator with a yield statement.

This is taken from an identical test in test_Iterable, in the same file.

> It would be good to have a versionadded notice for Reversible. 

Definitely; thanks for the catch. I'll add that for the next version of the patch.

> I think there should also be one for allowing None for all special methods.

I'm assuming you mean in collections.abc, not in the data model, right?

The problem is where to put it. The collections.abc docs don't even mention that some of the ABCs have subclass hooks that detect "implicit subclasses", much less tell you which ones do and don't, much less tell you which among those that do treat None specially. Until we add that documentation, there's really nothing to contrast with.

Maybe this means we need another bug where we rewrite the collections.abc docs to include all that information, and in the new documentation we can note what prior versions of Python did (or maybe prior versions of CPython--I doubt any major implementations were different, but without checking them all I wouldn't want to guarantee that)?

> Instead of self.assertEqual(list(reversed(R())), list(reversed([]))), why not check it is equal to an empty list directly?

This might be a case of following the parallelism with test_Iterable too far; I can change it.

> In test_contains.py, I would either write lambda: 0 in bc, or use the “with self.assertRaises()” form.

That makes sense; I'll do it.

> Finally, if setting a binary operator method to None means that operation is not available, I find it a bit surprising that doing this prevent the other operand’s method from being tried. I guess you don’t want to change the implementation, but perhaps the documentation of the binary operator methods could be clarified.

I definitely don't want to change the implementation unless there's a very good reason.

Also, if you think it through, from either angle, the way it's always worked makes perfect sense. None (in fact, anything that raises a TypeError when called) always blocks fallback, so it blocks fallback to other.__radd__. Alternatively, the rules for when + looks for __radd__ are very specific and reasonably simple, and TypeError is not one of the things that triggers it. 

Making None trigger __radd__ would require making one of those two rules more complicated. And what would the benefit be? If you want to trigger fallback, there's already a simple, well-documented, readable way to do that; we don't need another one.

And I think the note would be more likely to confuse someone who didn't need it (and maybe make him think he should be defining __add__ = None where he really shouldn't) than to help someone who did. Actual reasonable use cases for __add__ = None are rare enough that I think it's OK that someone has to understand what they're doing and be able to think through the rules and/or know what combinations to test via trial and error before they can use it.

But maybe a footnote would work? For example, in the sentence "These functions are only called if the left operand does not support the corresponding operation and the operands are of different types. [2]", we could add another footnote after "does not support the corresponding operation", something like this:

> [2] "Does not support" here means has no such method, or has a method that returns NotImplemented, as described above. Do not assign the method to None if you want to force fallback to the right operand's reflected method--that will instead have the opposite effect of explicitly _blocking_ such fallback.

Again, thanks for all the notes.
History
Date User Action Args
2016-01-05 07:33:19abarnertsetrecipients: + abarnert, gvanrossum, ncoghlan, r.david.murray, martin.panter, serhiy.storchaka
2016-01-05 07:33:18abarnertsetmessageid: <1451979198.22.0.84826645528.issue25958@psf.upfronthosting.co.za>
2016-01-05 07:33:18abarnertlinkissue25958 messages
2016-01-05 07:33:16abarnertcreate