Slice in Store Context
After 7 years of working with Python, there’s always something basica to learn… So I was playing around with the
ast module the other day; investigating something completely unrelated, but then I got genuinely nerd-sniped. I typed this into the REPL:
>>> import ast >>> tree = ast.parse('a[0:1]', mode='eval') >>> ast.dump(tree.body.value) "Subscript(value=Name(id='a', ctx=Load()), slice=Slice(lower=Num(n=0), upper=Num(n=1), step=None), ctx=Load())"
Ok, this is what I was expecting. Wait, why does the
Subscript() object have a
ctx attribute with a
Load() makes sense, but can we also have a slice in
Then I smacked myself in the face, of course you can – This is how assignments into lists work…
>>> tree = ast.parse('a = 4') >>> ast.dump(tree.body.targets) "Subscript(value=Name(id='a', ctx=Load()), slice=Index(value=Num(n=0)), ctx=Store())"
Nope, it looks like just a single element assignment is an
Index() object. That makes sense too. So let’s try an actual slice.
>>> tree = ast.parse('a[0:5] = a') >>> ast.dump(tree.body.targets) "Subscript(value=Name(id='a', ctx=Load()), slice=Slice(lower=Num(n=0), upper=Num(n=5), step=None), ctx=Store())"
Slice() in a store context; A random corner of Python I didn’t know about. It does pretty much what you’d expect: replaces a slice out of a list with the right hand side. For example (notice that the length of the slice doesn’t have to match the right hand side):
>>> a = [1, 2, 3, 4, 5] >>> a[1:3] = 'abc' >>> a [1, 'a', 'b', 'c', 4, 5]
Ok, let’s really have fun. We all know the recipe to reverse a list:
a = a[::-1] This is taking a slice and using a negative step to walk backwards. Pretty straight forward. But, we can also do this the other way around, walk the list forward, and slice it in backwards!
>>> a = [1, 2, 3, 4, 5] >>> a[::-1] = a >>> a [5, 4, 3, 2, 1]
It works! Since we can assign to lists with arbitrary steps, I can think of one obvious use for this:
>>> N = 50 >>> S = range(N + 1) >>> for i in xrange(2, int(N ** .5)): ... if S[i]: ... S[i + i::i] =  * (N / i - 1) ... >>> [x for x in S if x > 1] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 49]
It’s a horribly inefficient implementation of the Sieve of Eratosthenes! I’m sure there are legitimate uses for this feature, but it’s fun none the less.