On May 10, 2020, at 15:39, Christopher Barker <pythonchb@gmail.com> wrote:
Is there any way you can fix the reply quoting on your mail client, or manually work around it?
I'm trying -- sorry I've missed a few. It seems more and more "modern" email clients make "interspersed" posting really hard. But I hate bottom posting maybe even more than top posting :-( (gmail seems to have magically gotten worse in this regard recently)
It seems like the one place Google still sees (the remnants of) Yahoo as a competitor is who can screw up mailing lists worse.
It's also interesting to note (from another part of this thread) that slicing isn't part of the Sequence ABC, or any? "official" protocol?
If we still had separate __getitem__ and __getslice__ when ABCs and the idea of being clearer about protocols had come along, I’ll bet __getslice__ would have been made part of the protocol. But I suppose it’s a little too late for me to complain about a change that I think went in even before new-style classes. :)
I do see this, though not entirely sure what to make of it:
Yeah, the fact that sequences and mappings have identical methods means that from Python those two protocols are opt-in rather than automatic, while from C you have to be more prepared for errors after checking than with other protocols. Annoying, but not using the same syntax and dunders for indexing and keying would be a lot more annoying.
> Also, notice that this is true for all of the existing views, and none of them try to be un-featureful to avoid it.
But there is no full featured mapping-view that otherwise acts much like a mapping.
types.MappingProxyType. In most cases, type(self).__dict__ will get you one of these.
But of course this is a view of the whole dict, not a subset.
in theory, there *could* be -- if there was some nice way to specify a subset of a mapping without copying the whole thing -- I can't think of one at the moment.
Not in the stdlib, but for a SortedDict type, key-slicing makes total sense, and many of them do it—although coming up with a nice API is hard enough that they all seem to do it differently. (Obviously d[lo:hi] should be some iterable of the values from the keys lo<=key<hi, and obviously it should also be a subtree dict with just those keys, and it can’t be both, so you need at least one way to spell an alternative, and maybe as many as a dozen…)
I think the biggest question is actually the API. Making this a function (or a class that most people think of as a function, like most of itertools) is easy, but as soon as you say it should be a method or property of sequences, that’s trickier. You can add it to all the builtin sequence types, but should other sequences in the stdlib have it? Should Sequence provide it as a mixin? Should it be part of the sequence protocol, and therefore checked by Sequence as an ABC (even though that could be a breaking change)?
Here is where I think you (Andrew) and I (Chris B.) differ in our goals. My goal here is to have an easily accessible way to use the slice syntax to get an iterable that does not make a copy.
It’s just a small difference in emphasis. I want a way to get a non-copying slice, and I’d really like it to be easily accessible—I‘d grumble if you didn’t make it a member, but I’d still use it.
While we're at it, getting a sequence view that can provide an iterator, and all sorts of other nifty features, is great. But making it a callable in itertools (or any other module) wouldn't accomplish that goal.
Hmm, but maybe not that bad:
for i in itertools.seq_view(a_list)[::2]:
...
I still think I prefer this though:
for i in a_list.view[::2]:
...
Agreed. A property on sequences would be best, a wrapper object that takes slice syntax clearly back in second, and a callable that takes only islice syntax a very distant third. So if the first one is possible, I’m all for it.
My slices repo provides the islice API just because it’s easier for slapping together a proof of concept of the slicing part, definitely not because I’d want that added to the stdlib as-is.
However, there is one potential problem with the property I hadn’t thought of until just now: I think people will understand that mylist.view[2:] is not mutable, but will they understand that mystr.view[2:] is not a string? I’m pretty sure that isn’t a problem for seqview(mystr)[2:], but I’m not sure about mystr.view[2:].
So to all those questions: I say "yes" except maybe:
"checked by Sequence as an ABC (even though that could be a breaking change)" -- because, well, breaking changes are "Not good".
I wonder if there is a way to make something standard, but not quite break things -- hmm.
For instance: It seems to be possible to have Sequence provide it as a mixin, but not have it checked by Sequence as an ABC?
Actually, now that I think about it, Sequence _never_ checks methods. Most of the ABCs are automatic (structural): any type with the right methods is a subclass. But Sequence and Mapping are opt-in (nominal): only types that inherit from the ABC or register with it are subclasses. There are @abstractmethod checks, but those only test the methods required to use it as a mixin, not all the methods required to meet the protocol (because, when you’re inheriting, you automatically have those other methods so there’s no point checking for them).
I think people assume the protocol is everything the mixin provides, whether that’s correct or not, so if you did add a property to the mixin, you’d probably want to put a note in the docs saying that classes that register with Sequence are not required to support that property (but it is nice if you can). That might be (a) all you can do and (b) good enough.
For instance, I note that the Mapping ABC has .keys, .items, .values, and there are ABCs for MappingViews, but I can't see if it's defined anywhere that the Mapping methods have to produce View objects.
It’s not, just like it’s not defined that Sequence.__getitem__ has to accept slices or negative indices.
The only place I can think of where any protocol is defined in terms of exactly what behavior a method supports, rather than just having the method, is (I can’t remember where) iterable: a type is iterable if it has __iter__, or it has __getitem__ that works on all contiguous ints starting from 0 up until it raises IndexError. (But the Iterable ABC just checks for __iter__, so if you want it to accept an old-style iterable you have to register it manually.)
But notice that if you use the Mapping mixin to define the methods for you, it does make sure you get the right views. Maybe that’s sort of a precedent for what you’re looking to do?
>> People know they’re lazy, they know iterators are lazy, so they think they’re a kind of iterator, and the docs don’t ever make it clear why that’s wrong.
Right -- I think a lot of the confusion around the vocabulary is that people think of "iterators" as being "lazy", and the term gets used a lot when laziness is really the key point. (a lot of confusion like that around "generator" as well).
People don’t even have to misuse “generator” to mean “any iterator” or “any lazy thing” to be confusing; it’s always confusing except where something in the context makes it clear. The docs can’t even agree with themselves on whether it means a generator function or a generator iterator, not to mention whether normal functions that return a generator iterator are generator functions (and the recent change to @partial makes that even more fun) and whether types that meet the Generator protocol are generator iterators.
I think it’s a testament to how clear the concepts behind this stuff are that people manage to learn and internalize and use them despite the terminology. :)