Can't get around "IndexError: list index out of range"

E

erikwickstrom

Hi all,

I'm sorry about the newbie question, but I've been searching all
afternoon and can't find the answer!

I'm trying to get this bit of code to work without triggering the
IndexError.

import shutil, os, sys

if sys.argv[1] != None:
ver = sys.argv[1]
else:
ver = '2.14'

Of course, whenever I run it, I get list index out of range.

I'm coming from the php world where I can do:
if $_GET['var'] != Null {
$ver = $_GET['var'];
} else {
$ver = '2.14';
}

Can anyone tell me how to make this work in python?

Thanks!
Erik
 
L

Leif K-Brooks

I'm trying to get this bit of code to work without triggering the
IndexError.

import shutil, os, sys

if sys.argv[1] != None:
ver = sys.argv[1]
else:
ver = '2.14'

Catch it:

try:
ver = sys.argv[1]
except IndexError:
ver = '2.14'
 
S

Steven Bethard

I'm trying to get this bit of code to work without triggering the
IndexError.

import shutil, os, sys

if sys.argv[1] != None:
ver = sys.argv[1]
else:
ver = '2.14'

Something like::

if len(sys.argv) > 1:
ver = sys.argv[1]
else:
ver = '2.14'

It looks like you're trying to do argument parsing, though and for
anything more complicated than the above, you might prefer to use a real
argument parsing library like argparse_::

import argparse

parser = argparse.ArgumentParser(description='print the version')
parser.add_argument('ver', nargs='?', default='2.14',
help='the version number to print')

args = parser.parse_args()
print args.ver

Then from the command line::

$ script.py
2.14

$ script.py 3.14159265359
3.14159265359

$ script.py -h
usage: script.py [-h] [ver]

print the version

positional arguments:
ver the version number to print

optional arguments:
-h, --help show this help message and exit

And then you can feel good about yourself for also documenting your
command-line interface. ;-)

... _argparse: http://argparse.python-hosting.com/

STeVe
 
T

Terry Reedy

Leif K-Brooks said:
I'm trying to get this bit of code to work without triggering the
IndexError.

import shutil, os, sys

if sys.argv[1] != None:
ver = sys.argv[1]
else:
ver = '2.14'

Catch it:

try:
ver = sys.argv[1]
except IndexError:
ver = '2.14'

Or slice it:

if sys.argv[1:2] != []:
<etc>

tjr
 
S

Steve Holden

Hi all,

I'm sorry about the newbie question, but I've been searching all
afternoon and can't find the answer!

I'm trying to get this bit of code to work without triggering the
IndexError.

import shutil, os, sys

if sys.argv[1] != None:
ver = sys.argv[1]
else:
ver = '2.14'

Of course, whenever I run it, I get list index out of range.

I'm coming from the php world where I can do:
if $_GET['var'] != Null {
$ver = $_GET['var'];
} else {
$ver = '2.14';
}

Can anyone tell me how to make this work in python?
Well all the advice you've had so far seems good, but of course the
simplest way is just to test the length of the sequence before you try
to address its second element:

if len(sys.argv) > 1:
ver = sys.argv[1]
else:
ver = "2.14"

regards
Steve
 
E

erikcw

I ended up using len(sys.argv) > 1 for this particular problem. But I
think slicing is closer to the tool I was looking for.

I found a.has_key(k) or "k in a" for dictionaries - but haven't found
anything similar for lists. Does it exist?

I guess my example from php would technically be a dictionary in python
and not a list, it would nice to be able to quickly tell if a list key
existed or not.

Thanks!
Erik


Steve said:
Hi all,

I'm sorry about the newbie question, but I've been searching all
afternoon and can't find the answer!

I'm trying to get this bit of code to work without triggering the
IndexError.

import shutil, os, sys

if sys.argv[1] != None:
ver = sys.argv[1]
else:
ver = '2.14'

Of course, whenever I run it, I get list index out of range.

I'm coming from the php world where I can do:
if $_GET['var'] != Null {
$ver = $_GET['var'];
} else {
$ver = '2.14';
}

Can anyone tell me how to make this work in python?
Well all the advice you've had so far seems good, but of course the
simplest way is just to test the length of the sequence before you try
to address its second element:

if len(sys.argv) > 1:
ver = sys.argv[1]
else:
ver = "2.14"

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://holdenweb.blogspot.com
Recent Ramblings http://del.icio.us/steve.holden
 
G

Gabriel Genellina

I ended up using len(sys.argv) > 1 for this particular problem. But I
think slicing is closer to the tool I was looking for.

I found a.has_key(k) or "k in a" for dictionaries - but haven't found
anything similar for lists. Does it exist?

if 2 in [1,2,3]: print "Use the same (in) operator"
elif 'E' in ('E','r','i','k'): print "Works for any sequence"
elif 'o' in 'hello': print "Even strings"



Gabriel Genellina
Softlab SRL





__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas
 
H

hanumizzle

I ended up using len(sys.argv) > 1 for this particular problem. But I
think slicing is closer to the tool I was looking for.

I found a.has_key(k) or "k in a" for dictionaries - but haven't found
anything similar for lists. Does it exist?

As Gabriel Genellina observed, lists also may use the 'in' syntax.
Actually, any object that supports the method __contains__ can do
this, which means you may furnish your own in user objects.

What hasn't been addressed is efficiency. This is often a secondary
concern in a VHLL such as Python, but you may wish to know that using
the 'in' test on a large list repeatedly will slow down a program. You
may wish to use a set object instead, according to the application.
I guess my example from php would technically be a dictionary in python
and not a list, it would nice to be able to quickly tell if a list key
existed or not.

Yes, PHP arrays are associative (dicts). But lists (in the Pythonic
sense, aka 'vectors') do not have keys as such, only indices.

-- Theerasak
 
M

MonkeeSage

if 2 in [1,2,3]: print "Use the same (in) operator"
elif 'E' in ('E','r','i','k'): print "Works for any sequence"
elif 'o' in 'hello': print "Even strings"

This isn't really analogous is it? For "somedict.has_key(k)" or "k in
somedict", you don't need to know the value of somedict[k] ahead of
time. So you can avoid KeyError by asking if the key exists first
before trying to get the value. Wouldn't that be more like this for
lists (and other sequences):

def has_index(seq, index):
try:
seq[index]
return True
except IndexError:
return False

I've often wondered why there is no built-in method like that for
sequence objects. And also why not the equivalent of dict.get for other
sequences:

def get(seq, index, default=None):
if has_index(seq, index):
return seq[index]
else:
return default

Seems useful...

Regards,
Jordan
 
G

Gabriel Genellina

if 2 in [1,2,3]: print "Use the same (in) operator"
elif 'E' in ('E','r','i','k'): print "Works for any sequence"
elif 'o' in 'hello': print "Even strings"

This isn't really analogous is it? For "somedict.has_key(k)" or "k in
somedict", you don't need to know the value of somedict[k] ahead of
time. So you can avoid KeyError by asking if the key exists first
before trying to get the value.

The meaning comes from the most common usage. For a list, you want to
know if an object is contained in the list (not if an index is in
range!). For a dictionary, you usually want to know if it maps
anything to a given key (not if any key maps to that value!). These
are the most common operations, and that's why they have the simple
sintax "a in b". [BTW, usage of operator "in" as "key in dict" is
rather new to Python; has_key() were the only way to test for key
existence some time ago].
Wouldn't that be more like this for
lists (and other sequences):

def has_index(seq, index):
try:
seq[index]
return True
except IndexError:
return False

I've often wondered why there is no built-in method like that for
sequence objects.

Because it's not needed at all: valid sequence indexes are *exactly*
range(len(seq)). This is the basic point of being a sequence: when
indexes are not contiguous, in fact you have a mapping, not a sequence.
And also why not the equivalent of dict.get for other
sequences:

def get(seq, index, default=None):
if has_index(seq, index):
return seq[index]
else:
return default

Seems useful...

Sometimes, maybe... But since you can write it efficientely in a few
lines when needed, I don't see the need to put it into the core language.


--
Gabriel Genellina
Softlab SRL





__________________________________________________
Preguntá. Respondé. Descubrí.
Todo lo que querías saber, y lo que ni imaginabas,
está en Yahoo! Respuestas (Beta).
¡Probalo ya!
http://www.yahoo.com.ar/respuestas
 
M

MonkeeSage

The meaning comes from the most common usage.

I wasn't suggesting that the "in" keyword have a different sematic for
sequence types. I was just saying that regarding the question whether
there is anything similar to "dict.has_key / k in dict" for lists, the
"in" keyword is not semantically analogous.
Because it's not needed at all: valid sequence indexes are *exactly*
range(len(seq)). This is the basic point of being a sequence: when
indexes are not contiguous, in fact you have a mapping, not a sequence.

True. But valid dictionary keys are exactly d.keys(). The has_key
method is just sugar.
Sometimes, maybe... But since you can write it efficientely in a few
lines when needed, I don't see the need to put it into the core language.

Couldn't the same be said for dictionaries? I could write for
sequences:

if index < len(seq) and seq[index]: ...

But I could also write for dictionaries:

if key in dic.keys() and dic[key]: ...

I just wonder why the syntactic sugar was added for dicts, but not for
sequence types.

Regards,
Jordan
 
F

Fredrik Lundh

MonkeeSage said:
True. But valid dictionary keys are exactly d.keys(). The has_key
method is just sugar.

for what? are you sure you're using "sugar" as it is usually used when
talking about computer languages?

</F>
 
M

MonkeeSage

for what?

key in self.keys()

And d.get() looks like sugar for:

if self.has_key(key):
return self[key]
else:
return default_value

Why not have the same sugar for sequence types? E.g.,

def has_index(self, index):
return index < len(self)

def get(self, index, default=None):
if self.has_index(index):
return self[index]
return default

I understand not wanting to add bloat without use cases and / or when
the programmer can easily implement the functionality themselves; but I
don't see why the sugar would be added for dict but not sequence types.
The fact of easy implementation by the programmer without the
convenience method is the same in both cases, and I would assume (but
don't claim to know) that one could find many use cases for, e.g.,
list.has_index() / . get().

Regards,
Jordan
 
D

Duncan Smith

MonkeeSage said:
key in self.keys()

[snip]

No. The above constructs a list of keys and searches the list for the
key, O(n). "key in somedict" is a lookup, O(1).

Duncan
 
M

MonkeeSage

No. The above constructs a list of keys and searches the list for the
key, O(n). "key in somedict" is a lookup, O(1).

My point wasn't in regard to implementation details, but in regard to
convenience methods. Obviously the sugary dict methods are tweaked for
the best performance (one would hope!), as would be sugary sequence
methods were they to be added. What I was wondering is why
dict.has_key() and get() are there but not list.has_index() and get().

Regards,
Jordan
 
S

Steven D'Aprano

I wasn't suggesting that the "in" keyword have a different sematic for
sequence types. I was just saying that regarding the question whether
there is anything similar to "dict.has_key / k in dict" for lists, the
"in" keyword is not semantically analogous.

Are you just making a philosophical point? In which case I agree: *if* you
make the analogy "a dictionary key is analogous to a sequence index",
*then* the operation of "in" isn't semantically analogous between mappings
and sequences. But why should it be?

In both mappings and sequences, "in" tests for membership. But *what* it
tests for membership is different. There's no shame there.

True. But valid dictionary keys are exactly d.keys(). The has_key
method is just sugar.


A little bit of history might be useful here. Originally, if you wanted to
test for key membership with a dict, you had three choices:

(1) Easier To Ask Forgiveness Than Permission:

try:
mapping[key]
except KeyError:
print "Oops, that's not a key!"


(2) mapping.has_key(key), which inspected the dict's internals to
determine whether key was valid or not.

(3) Build a list of keys, then test whether the key was in the list:

key in mappings.keys()


Obviously all three methods had their disadvantages. The first required
catching an exception, which is expensive, and is less than clear. The
second is a magic method that needs to be remembered by the developer,
and breaks the equivalence of mappings and sequences. The third means
building, and throwing away, a temporary list of keys.

But after types and classes were unified, dicts grew a __contains__
method for subclassing. If you want syntactic sugar, "x in obj" is
"just" syntactic sugar for obj.__contains__(x) (but note the scare quotes
around just: one person's syntactic sugar is another person's essential
syntactic feature).
 
S

Steven D'Aprano

My point wasn't in regard to implementation details, but in regard to
convenience methods. Obviously the sugary dict methods are tweaked for
the best performance (one would hope!), as would be sugary sequence
methods were they to be added. What I was wondering is why
dict.has_key() and get() are there but not list.has_index() and get().

Because they aren't needed often, and when they are, they are easy to
implement?

Instead of list.has_index(n), write 0 <= n < len(list).

If you want to allow for negative indices as well, write
-len(list) <= n < len(list).


It is hard to see where list.get(index, default) would be useful, since
accessing an index out of range of a list is generally an error, unlike
accessing a missing key. But I like symmetry, and for symmetry I wouldn't
object to sequences gaining a get method too. Not that I care about it
enough to put in a feature request or a PEP, but if somebody else did, I
wouldn't object.

(Note, though, that accessing a *slice* out of range is not an error, but
returns an empty list.)

get() is easy enough to implement. Feel free to turn it into a method
of a collection class if you like.

def get(mapping_or_sequence, key_or_index, default=None):
try:
return mapping_or_sequence.get(key_or_index, default)
except AttributeError:
# probably a sequence
try:
return mapping_or_sequence[key_or_index]
except IndexError:
return default

Not every piece of functionality needs to be a built-in.
 
M

MonkeeSage

Are you just making a philosophical point? In which case I agree: *if* you
make the analogy "a dictionary key is analogous to a sequence index",
*then* the operation of "in" isn't semantically analogous between mappings
and sequences. But why should it be?

It shouldn't, and I'm making a pragmatic (not merely philosophic) point
regarding the OP's question whether there is a "similar" list method to
dict.has_key.
In both mappings and sequences, "in" tests for membership. But *what* it
tests for membership is different. There's no shame there.

I know / agree.
Originally, if you wanted to
test for key membership with a dict, you had three choices:

I know.

Because they aren't needed often, and when they are, they are easy to
implement?

More often and easier to implement than dict.has_key / get?
It is hard to see where list.get(index, default) would be useful, since
accessing an index out of range of a list is generally an error, unlike
accessing a missing key.

Uh, no. KeyError.
But I like symmetry, and for symmetry I wouldn't
object to sequences gaining a get method too. Not that I care about it
enough to put in a feature request or a PEP, but if somebody else did, I
wouldn't object.

Me neither. :)
get() is easy enough to implement. Feel free to turn it into a method
of a collection class if you like.

I already did, see previous posts.
Not every piece of functionality needs to be a built-in.

Agreed. but why implement a certain functionality in one place but
leave it out of another?

Regards,
Jordan
 
D

Duncan Smith

MonkeeSage said:
My point wasn't in regard to implementation details, but in regard to
convenience methods. Obviously the sugary dict methods are tweaked for
the best performance (one would hope!), as would be sugary sequence
methods were they to be added. What I was wondering is why
dict.has_key() and get() are there but not list.has_index() and get().

Regards,
Jordan

All I can say is that, I personally, would have little use for those
list methods. Those involved in the design of the language will no
doubt have much better reasons than this.

Duncan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top