kc64 kc64 - 8 days ago 6
Python Question

What does the slice() function do in Python? (compared to slice notation)

I wanted to comment on the accepted answer on the post of the same name but I'm way too green.

That answer, "a[x:y:z] is gives the same result as a[slice(x, y, z)]", is not proving true in my attempts so I am seeking a deeper understanding of the differences between slice() and the slice notation.

I have a serial protocol that has a message body like this: Q0134CA24B.

If I want to collect elements of that protocol, it would be very nice to do this:

>>> str = 'Q0134CA24B'
>>> cmd = slice(0,1)
>>> str[cmd]
'Q'
>>> cs = slice(-2,0)
>>> str[cs]
''
>>> cs
slice(-2, 0, None)
>>> str[cs]
''
>>> str[-2:None:None]
'4B'


So, what am I doing wrong? Is slice() just limited compared to slice notation? This would be very useful to me since I am frequently working in serial protocols and defining character fields with slice() would be a pythonic way to pass this representation around.

Answer

The two notations are consistent, maybe you are confusing 0 with None? 0 is a position, or actual length, None is the absence of that. To quote the source code (Objects/sliceobject.c): "start, stop, and step are python objects with None indicating no index is present."

None and 0 are the same for a start position.

>>> s = 'Q0134CA24B'
>>> s[:1]
'Q'
>>> s[0:1]
'Q'

For length, None means "through to the end of the sequence", whereas 0 means a length of zero.

>>> s[1:]
'0134CA24B'
>>> s[1:0]
''

For step, None means one, but 0 is invalid and will raise a ValueError, and that is the same if you are using [ ] notation or slice().

Taking your examples (str is a bad name for a variable):

>>> s = 'Q0134CA24B'
>>> cmd = slice(0,1)
>>> s[cmd]
'Q'
>>> s[0:1]
'Q'

>>> cs = slice(-2,0)
>>> s[cs]
''
>>> s[-2:0]
''
>>> cs
slice(-2, 0, None)

>>> s[-2:None:None]
'4B'
>>> s[-2::]
'4B'
>>> cd = slice(-2,None,None)
>>> str[cd]
'4B'

There is no inconsistency there.