> That applies to many interface checks. Both the built-in callable() and
the Callable ABC don't tell you what arguments the object accepts, or
what it does; the Sequence ABC check doesn't tell you what valid indexes
are accepted.
Sure — and Callable is probably the closest ABC to this proposal there is.
But while I’m having trouble putting my finger on it, Callable seems to have a special place in the language that makes it important.
While __getitem__ could do just about anything, I’d bet most folks would consider to be bad form to use it for something that did not “feel” like indexing.
People may assume that valid indexes go from 0 through
len-1 but we can make sequences that work with 1-based sequences, or
like Fortran, with any bounds at all.
Sure, but they should all raise IndexError if you violate the rules.
Including virtual "sequences" that accept indexes from -infinity to
infinity, with no length.
"Consenting adults" applies. The ABC checks only test for the presence
of an interface, they don't necessarily make guarantees about what the
interface will do.
Sure, but again, what’s the point here? What’s the use case for knowing that the object at hand will allow you to pass something into the square brackets, but nothing else?
> So if you think you *may* have a "callable_with_an_integer" -- the thing to
> do is:
>
> try:
> result = squares[5]
> except TypeError:
> print("Opps, couldn't do that")
I know that's meant in good faith, but please be careful of telling me
what I should do on the basis of a wild guess of what my needs are. I've
been programming in Python since 1.5 was the latest and greatest, and I
think I'm capable of judging when I want to use a try...except EAFP
check rather than a LBYL check for an interface.
I was using “you” rhetorically— but more importantly, I was suggesting that that was the how to do EAFTP, not that you should do EAFTP. The OP has posted a more convoluted form.
why Python supports ABCs and isinstance. If you
want to argue against that, that ship has not only sailed but it's
already docked at the destination and the passengers disembarked :-)
Interestingly, use of ABCs seems to be really growing with static type checking — relatively new.
> Now that I think about it a bit more, that example *could* make sense, but
> only if what you are trying to do is make an indexable lazy-evaluated
> infinite sequence of all the squares --
Well spotted :-)
So then you want an “IndexableIterable” ABC or some such. That might be a useful ABC.
Why do I think it would be more useful? Because it would specify more than just “you can put any old thing into the square brackets”.
you can essentially create
> types that have any arbitrary combination of functionality -- do we need an
> ABC for every one? Obviously not.
I don't think it is so obvious.
Clearly we can't have an ABC for every imaginable combination of magic
methods. There would be hundreds. What would we name them?
That’s why I said it was obvious :-)
And we should (so I am arguing) have ABCs for the underlying building
blocks, the individual magic methods themselves. Developers can then
combine those building blocks to make their own application-specific
combinations.
But this is s very different proposal! If I have it right, you are now suggesting that there be an ABC for every magic method (there are a LOT).
Why? So we can use isinstance() to check for a particular protocol, rather than try:except or hasattr()
But this seems to be really stretching what Python ABCs are about.
OK, that ship has sailed, and no, I’m not particularly happy about it. But you can make your own ABC with the particular combination of attributes you want — wouldn’t that make more sense than asking your users to call isinstance with 10 ABCs?
Which brings me back to the original proposal:
1) why not make your own ABC?
And
2) can someone provide even a single use case? We’ve seen one example of a class that implemented __getitem__ in an unconventional way, but not an example of how having an ABC for it would be actually useful.
-CHB