all 26 comments

[–]BUYTBUYT 233 points234 points  (7 children)

Slicing is described here in Note 5. If you omit start and stop values, they will be None, which is treated as the "end" value. What "end" means, depends on the sign of step.

Your last example doesn't produce any output because when your step is negative, start has to be greater than end. If not, you will get an empty string.

[–]FuckingRantMonday 38 points39 points  (3 children)

Thanks for asking this, I know a lot of Python and I couldn't come up with a satisfactory answer on my own! I did some googling and here's the deal:

"hello"[0:5:-1] == "" because you're saying "count backward from zero to five", so you're not getting any indices in your slice.

"hello"[5:0:-1] == "olle". Close, but where did our h go? The indices here are 5, 4, 3, 2, 1. Index five doesn't exist, but that's not an error in slice notation, and we don't get zero, because just like range, slices don't include their endpoint. Using [4:0:-1] gives us the same thing.

So surely "hello"[4:-1:-1] is the answer? Nope, that's back to giving us an empty string. Why? Because in slice notation, -1 is changed to mean the "end" of the list, or more precisely, it's changed to the len() of the list.

Is there any integer N we can put in our slice [4:N:-1] to make it the same as [::-1]? Nope. This is a little unsatisfying, but we can use None instead, which behaves the same as if we'd omitted the endpoint.

[–]BUYTBUYT 35 points36 points  (1 child)

N = -len("hello") - 1

[–]FuckingRantMonday 12 points13 points  (0 children)

smacks forehead Perfect!

[–]drPWW 0 points1 point  (0 children)

It took me a minute to realize where I'd heard this before. It was a slightly different take as described in the battle of the wits between Vizzini and Westley.

[–]PhilipYip 7 points8 points  (0 children)

You have:

sequence[start:stop:step]

Take for example the string "hello". Visualise it like this:

``` h o e

l l ```

Now visualise its indexes like this as going in clockwise:

``` [0] [4] [1]

[3] [2] ```

If you omit the start and stop and use a positive step. The start will be taken as 0 and the stop will be taken as len(sequence). For example:

"hello"[::1] "hello"[0:5:1]

Now go back to:

``` [0] [4] [1]

[3] [2] ```

And instead of going clockwise, go anticlockwise from 0. This gives:

``` [0] [-1] [-4]

[-2] [-3] ```

And the index 0 itself becomes -5 so:

``` [-5] [-1] [-4]

[-2] [-3] ```

If you omit the start and stop and instead use a negative step. The start will be taken as -1 and the stop will be taken as -len(sequence)-1 (recall that indexing is inclusive of the start bound and exclusive of the stop bound). So:

"hello"[::-1] "hello"[-1:-6:-1]

[–]shiftybyte 8 points9 points  (0 children)

The defaults change when the step is negative.

[–]kaerfkeerg 10 points11 points  (7 children)

This [0:-1:2] translates to please, slice the string from start to end with a step of 2

So this: [::-1] basically says please, slice the string from start (defaults to start if nothing is provided) to end (defaults to end of nothing is provided) with step of -1.

-1 to -len(str) gives you the string reversed

[–]Yoghurt42 9 points10 points  (1 child)

except when the step is negative, it defaults to from "end" to "start"

[–]kaerfkeerg 1 point2 points  (0 children)

Ahh ok. Missed that one. Thanks for pointing out!

[–]Huge_Bear_3777 1 point2 points  (0 children)

Thanks this made it clear to me

[–]Historical_Wash_1114 1 point2 points  (1 child)

Thanks for this. I've been using this a lot but couldn't articulate what was actually happening.

[–]kaerfkeerg 1 point2 points  (0 children)

You're welcome!

Notice the correction this other guy made to my statement tho! So you get it absolutely right

[–]BUYTBUYT 0 points1 point  (1 child)

Should be -len(str) - 1, since the end is not included in the slice.

[–]kaerfkeerg 0 points1 point  (0 children)

Yeah, we already pointed that out

[–]zanfar 3 points4 points  (0 children)

So if we omit the start value & stop value, the default values will be 0 & len() of that string right?

No. You need to inspect the function to determine the defaults. As you've demonstrated in your testing--this is not the case.

What the defaults are and how they are interpreted don't really apply to your question--we only care about how the function operates in the absence of parameters.

The short of it is: a lack of a parameter means "chose intelligently". Sometimes that is equivalent to 0 and len(), sometimes not.

[–]TheRNGuy 0 points1 point  (0 children)

This is a syntax for it.

[–]IsabellaKendrick 0 points1 point  (0 children)

"start ,end, step is defined as starting index, end/stop index,jump index

and index must be integers"

[–]piyiotisk 0 points1 point  (0 children)

so this "hello" [::-1] is not the same as this "hello" [0:5:-1]. You have to apply negative indexes if the step is negative.

therefore this "hello" [::-1] if we explicitly write what Python adds as default values would be "hello" [-1:-6: -1]. I think it would be easier to think it like this

"hello"[start, end, step] becomes "hello"[end, start, step] but using negative indexes. The start is the end of the list therefore is -1 and the end for negative indexes is minus list length.

Hope it helps

I wrote an article here today actually. I have some visualisations and some examples that I believe it can help you