Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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 :).

None is the usual representation for "parameter not given", so you can communicate the fact to a function. You will often see functions or methods declared like this

def f(p=None):
    if f is None:
        f = some_default_value()

I guess this makes the choice clear: Be using None you can tell the slicer to use its default values.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top