It's not a real world program but I would like to know why it can't be done.
I was thinking about numpy.r_
object and tried to do something similar but just making a class and not instantiating it.
a simple code (has some flaws) for integers could be:
class r_:
@classmethod
def __getitem__(clc, sl):
try:
return range(sl)
except TypeError:
sl = sl.start, sl.stop, sl.step
return range(*(i for i in sl if i is not None))
but as I try to do r_[1:10]
i receive TypeError: 'type' object is not subscriptable
.
Of course the code works with r_.__getitem__(slice(1,10))
but that's not what I want.
Is there something I can do in this case instead of using r_()[1:10]
?
What you are trying to do is like
list[1:5]
orset[1:5]
=) The special__getitem__
method only works on instances.What one would normally do is just create a single ("singleton") instance of the class:
Now you can do:
You can also use metaclasses, but that may be more than is necessary.
Then you do need metaclasses.
Demo:
If you pass in
r_[1:5]
you will get aslice
object. Dohelp(slice)
for more info; you can access values likekey.stop if isinstance(key,slice) else key
.Define
__getitem__()
as a normal method inr_
's metaclass.The reason for this behavior lies in the way how special methods like
__getitem__()
are lookup up.Attributes are looked up first in the objects
__dict__
, and, if not found there, in the class__dict__
. That's why e.g. this works:Methods that are defined in the class body are stored in the class
__dict__
:So far there's nothing surprising here. When it comes to special methods however, Python's behavior is a little (or very) different:
The error messages are very different. With Test2, Python complains about an unbound method call, whereas with Test3 it complains about the unsubscriptability.
If you try to invoke a special method - by way of using it's associated operator - on an object, Python doesn't try to find it in the objects
__dict__
but goes straight to the__dict__
of the object's class, which, if the object is itself a class, is a metaclass. So that's where you have to define it:There's no other way. To quote PEP20: There should be one-- and preferably only one --obvious way to do it.
The protocol for resolving
obj[index]
is to look for a__getitem__
method in the type ofobj
, not to directly look up a method onobj
(which would normally fall back to looking up a method on the type ifobj
didn't have an instance attribute with the name__getitem__
).This can be easily verified.
I don't know why exactly it works this way, but I would guess that at least part of the reason is exactly to prevent what you're trying to do; it would be surprising if every class that defined
__getitem__
so that its instances were indexable accidentally gained the ability to be indexed itself. In the overwhelming majority of cases, code that tries to index a class will be a bug, so if the__getitem__
method happened to be able to return something, it would be bad if that didn't get caught.Why don't you just call the class something else, and bind an instance of it to the name
r_
? Then you'd be able to dor_[1:10]
.