Is there something internal in python that treats arguments passed to __getitem_
_
differently, and automatically converts start:stop:step
constructs into slices?
Here's a demonstration of what i mean
class ExampleClass(object):
def __getitem__(self, *args):
return args
def __call__(self, *args):
return args
def randomMethod(self, *args):
return args
a = ExampleClass()
#this works
print a[3:7:2, 1:11:2]
#syntax error on the first colon
print a.randomMethod(3:7:2, 1:11:2)
print a(3:7:2, 1:11:2)
#these work
print a.randomMethod(slice(3,7,2), slice(1,11,2))
print a(slice(3,7,2), slice(1,11,2))
Is it simply that the interpreter searches for instances of start:stop:step
inside []
, and swaps them out for slice(start, stop, step)
? The documentation simply says:
The bracket (subscript) notation uses slice objects internally
Is this one of the python internal bits that i can't alter the behaviour of? Is it possible to make other functions take slice objects usign the start:stop:step
shorthand?*
*I've seen the other question, Can python's slice notation be used outside of brackets?, but that just does it using a custom class, which i could easily do. What i want is a way to just use start:stop:step
without having to wrap it in anything else.
SIDE NOTE:
It also apears that all arguments inside [...]
are packaged up into a tuple
, somewhat as if it were doing [*args]
-> __getitem__(args)
.
class ExampleClass2(object):
def __getitem__(self, arg):
return arg
def __call__(self, arg):
return arg
b = ExampleClass2()
print b["argument 1", 2:4:6,3] # ('argument 1', slice(2, 4, 6), 3)
print b(slice(3,7,2), slice(1,11,2)) # TypeError: __call__() takes exactly 2 arguments (3 given)
The Python grammar defines when you can use the slice operator:
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [',']
subscript: test | [test] ':' [test] [sliceop]
sliceop: ':' [test]
test
is pretty much any expression, but it is only inside a subscriptlist
that you can use the slice operator. So yes, the square brackets when used for subscripting are what matter, but square brackets used for lists won't magically allow you to write a slice, nor can you put a slice inside an arbitrary expression that just happens to be inside a subscript.
If you want slices when you aren't subscripting something you'll have to write slice(a,b,c)
.
np.lib.index_tricks
contains several 'functions' that accept this ::
inputs, e.g. np.mgrid
, np.r_
, np.s_
.
They are actually implemented as instances of classes, with __getitem__
definitions. And they are 'called' with brackets.
np.s_[2::2] # slice(2, None, 2)
np.r_[-1:1:6j, [0]*3, 5, 6] # array([-1. , -0.6, -0.2, 0.2, ... 6. ])
mgrid[0:5,0:5]
I don't normally use them, but they are an interesting example of how __getitem__
can be exploited.
np.insert
is an example of a function that generates indexing tuples that include slices. np.apply_along
also:
i = zeros(nd, 'O')
...
i[axis] = slice(None, None)
...
i.put(indlist, ind)
...arr[tuple(i.tolist())]
http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html has a relevant note:
Remember that a slicing tuple can always be constructed as
obj
and used in thex[obj]
notation. Slice objects can be used in the construction in place of the[start:stop:step]
notation. For example,x[1:10:5,::-1]
can also be implemented asobj = (slice(1,10,5), slice(None,None,-1)); x[obj]
. This can be useful for constructing generic code that works on arrays of arbitrary dimension.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With