Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `for x in list[None:None]:` work?

Tags:

python

slice

I have a script that attempts to read the begin and end point for a subset via a binary search, these values are then used to create a slice for further processing.

I noticed that when these variables did not get set (the search returned None) the code would still run and in the end I noticed that a slice spanning from None to None works as if examining the entire list (see example below).

#! /usr/bin/env python
list = [1,2,3,4,5,6,7,8,9,10]
for x in list[None:None]:
  print x

Does anyone know why the choice was made to see the list[None:None] simply as list[:], at least that's what I think that happens (correct me if I'm wrong). I personally would think that throwing a TypeError would be desirable in such a case.

like image 418
Bas Jansen Avatar asked Apr 07 '14 15:04

Bas Jansen


2 Answers

Because None is the default for slice positions. You can use either None or omit the value altogether, at which point None is passed in for you.

None is the default because you can use a negative stride, at which point what the default start and end positions are changed. Compare list[0:len(list):-1] to list[None:None:-1], for example.

Python uses None for 'value not specified' throughout the standard library; this is no exception.

Note that if your class implements the object.__getitem__ hook, you'll get passed a slice() object with the start, end and stride attributes set to None as well:

>>> class Foo(object):
...     def __getitem__(self, key):
...         print key
... 
>>> Foo()[:]
slice(None, None, None)

Since Foo() doesn't even implement a __len__ having the defaults use None is entirely logical here.

like image 159
Martijn Pieters Avatar answered Oct 13 '22 11:10

Martijn Pieters


I also think that list[None:None] is interpreted as list[:]. This is handy behavior because you can do something like this:

return list[some_params.get('start'):some_params.get('end')]

If the list slicing wouldn't work with None, you would have to check if start and end were None yourself:

if some_params.get('start') and some_params.get('end'):
    return list[some_params.get('start'):some_params.get('end')]
elif some_params.get('start'):
    return list[some_params.get('start'):]
elif end:
    return list[:some_params.get('end')]
else:
    return list[:]

Fortunately this is not the case in Python :).

like image 31
gitaarik Avatar answered Oct 13 '22 11:10

gitaarik