IndexError: list index out of range - when it's clearly not

2k Views Asked by At

Pretty straight forward random password generating program.

I am generating 8 unique random numbers assigning those numbers to a variable and using that variable to print out a unique character from the alpha list.

The problem is that I am getting a "IndexError: list index out of range" error some of the times I'm running the program. I double checked and the the numbers that it's saying are out of range are totally in range since they are either 3, or 55, or etc. And I think the IndexError only pops up for the alpha list (e.g. alpha[c5]) not the actual nums list.

What am I missing? Please be gentle, I am new to programming. Sorry if this is a stupid question.

from random import random, sample

alpha = ['A','B','C','D','E','F','G','H','I','J',\
'K','L','M','N','O','P','Q','R','S','T','U','V','W',\
'X','Y','Z','a','b','c','d','e','f','g','h','i','j',\
'k','l','m','n','o','p','q','r','s','t','u','v','w',\
'x','y','z','0','1','2','3','4','5','6','7','8','9']

nums = sample(range(0,63),8)

print(nums)

c1 = nums[0]
c2 = nums[1]
c3 = nums[2]
c4 = nums[3]
c5 = nums[4]
c6 = nums[5]
c7 = nums[6]
c8 = nums[7]

print(alpha[c1],alpha[c2],alpha[c3],alpha[c4],alpha[c5],alpha[c6],\
alpha[c7],alpha[c8],end='')
3

There are 3 best solutions below

0
On

That 63 should be a 62, standard one-off error. Easy fix: nums = sample(range(0, len(alpha)), 8) (or more concisely, nums = sample(range(len(alpha)), 8)).

You’ll achieve your result with an even more concise one-liner: print(sample(alpha, 8)) that samples your elements directly, forgoing the need for a range.

Checkout the docs of random.sample for more usage tips. https://docs.python.org/3/library/random.html#functions-for-integers

0
On

nums = sample(range(0,63),8)

This means: choose 8 values that are within the range between 0 and 63, not inclusive - which you will then use to index into alpha.

This is needlessly complex. Just sample alpha directly:

letters = sample(alpha, 8)

That's how the method is supposed to work. There is nothing magic about range. It is not part of the language's syntax, and it doesn't cause any function or language construct to behave in a special way. It's just another object. The point of random.sample is that you start with a sequence (something that, conceptually, contains multiple values in a defined order) and you get some of its elements. A range is a sequence. But so is a list, or a string.

By trying to specify the length, you only add complexity and a source of bugs. There is no reason to do any indexing like this.


But to answer the actual questions/concerns raised:

some of the times I'm running the program

Well, yes, of course. You're picking values randomly, and almost all of them are valid.

I double checked and the the numbers that it's saying are out of range are totally in range

No; the numbers that don't cause the problem are in range. If they were out of range, then you wouldn't get to see the value after you tried to index with it, because the problem would happen first.

Unless you checked all the values before using them to index (which your print statement clearly doesn't do), and waited until you had a run of the program where the error occurred, and saw that on that run, all the values were valid, you don't have any evidence that "the values are in range".

You don't know anything about "the numbers that it's saying are out of range" because you don't know which number it's saying is out of range. The reason you don't know this is because the error message doesn't say the value that caused the problem. (This is, in my view, a shortcoming of the Python built-ins; it does show you the analogous information when you try to use a dict and get a KeyError.)

You could potentially find out by using a try block to wrap each attempt at indexing:

try:
    print(f'the first letter is {alpha[c1]}')
except IndexError:
    print(f'c1 is equal to {c1}, which is not a valid index for alpha')

But as you can imagine, this becomes really tedious really quickly. It's better not to have to hunt down bugs like this, by writing your code in a way that cannot have such bugs in the first place.

Do not use indexes if you have a simple way to avoid them.

And I think the IndexError only pops up for the alpha list (e.g. alpha[c5]) not the actual nums list.

Correct. nums has 8 elements, because of how it was created via random.sample. You get elements 0 through 7 inclusive, which are all valid indices. Those numbers are hard-coded and cannot fail.

The resulting values in c1 etc. are decided randomly. They can randomly end up being invalid.

0
On

You can use the len of alpha instead for your range

nums = sample(range(0, len(alpha)), 8)