0

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='')
Dharman
  • 30,962
  • 25
  • 85
  • 135
max d
  • 21
  • 1
  • 1
  • 4
  • Instead of creating a `sample` of indices into `alpha`, why not directly create a `sample` of the elements of `alpha`? – Karl Knechtel Oct 19 '20 at 05:36
  • Anyway. How many elements are in `alpha`? Count them. Do the bounds of your `range` make sense considering that? Explain that. – Karl Knechtel Oct 19 '20 at 05:38
  • " 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." Okay, so every time you run the program, you generate 8 index values, and the error only occurs sometimes. Did it occur to you that only one of the values has to be invalid to cause an error? So most of the time you won't see a problem if you just check the values, and even if a bad value was chosen, most of them will still be okay? Did you try to think of a way to check the value *when the problem occurs*, *using the value that cause the problem*? – Karl Knechtel Oct 19 '20 at 05:40
  • (Hint: Do you know what `try` does in Python?) But really, *just sample the values directly*. Unless there's some reason you're *expecting* indices in this range to always work. Let me put on my magic guessing hat: are you eventually trying to implement some kind of base-64 encoding? In that case, *the standard library already provides this, in a way that conforms to the base-64 standard*. – Karl Knechtel Oct 19 '20 at 05:41
  • 1
    Rule #1 of programming: if the computer says your code is wrong, then your code is wrong. If you are getting an index out of bounds error, then the index *is* out of bounds. There is not much use disputing it. – kaya3 Oct 19 '20 at 05:46
  • As far as I understand the range(0,63) function is going to return numbers between 0 and 62. The alpha has indices of 0 and 61, since it contains 62 items... so I guess that was my mistake. Thanks for nudging me in the right direction @KarlKnechtel. – max d Oct 19 '20 at 05:53
  • OP miscounted the alpha array by 1, no need to get the knives out. – tdelaney Oct 19 '20 at 05:56

3 Answers3

2

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

Alex Walczak
  • 1,276
  • 1
  • 12
  • 27
1

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.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
1

You can use the len of alpha instead for your range

nums = sample(range(0, len(alpha)), 8)
tdelaney
  • 73,364
  • 6
  • 83
  • 116