I’m teaching myself Python 3.2 and I’m trying to make a program to match a list of names. pList is a multidimensional list with a string at column 0, an integer at column 1, and a boolean at column 2. However, whenever I try and call this function (which only runs if the number of rows in the list is even), I get a TypeError.
Traceback (most recent call last):
File "C:\Users\METC\Dropbox\assassins.py", line 150, in <module>
main()
File "C:\Users\METC\Dropbox\assassins.py", line 11, in main
update(ops, pList)
File "C:\Users\METC\Dropbox\assassins.py", line 125, in update
b = match(pList)
File "C:\Users\METC\Dropbox\assassins.py", line 47, in match
q, p = 0
TypeError: 'int' object is not iterable
Any help would be appreciated, but keep in mind I’m a beginner with the language, so be gentle. 🙂 I don’t mind if you get too technical though; I have experience with computer science.
def match(pList):
b = []
z = len(pList)-1
for x in range(z):
b.append([pList[x][0],0])
for x in range(z):
isValid = False
q, p = 0
while isValid == False:
q = random.randint(0, z)
print('q is ' + str(q))
if q > z:
isValid = False
elif q < 0:
isValid = False
elif pList[q][1] == True:
isValid = False
else:
isValid = True
isMatch = False
while isMatch == False:
if pList[q][1] == False:
isValid = False
while isValid == False:
p = random.randint(0,z)
print('p is ' + str(p))
if p > z:
isValid = False
elif p < 0:
isValid = False
elif pList[p][2] == True:
isValid = False
else:
if q == p:
isValid = False
else:
isValid = True
print('match valid')
b[q][1] = pList[p][0]
isMatch = True
print('')
return b
You’ve made the logic far, far too complicated, to the point where I’m going to have to make several passes to get it down to size and show you what you’re doing wrong.
First, we’ll fix the actual reported error, as the others noted. At the same time, we’ll apply a simple principle: don’t compare to boolean literals. You don’t say “if it is true that it is raining, I will need an umbrella”. You say “if it is raining, I will need an umbrella”. So cut out the extra stuff.
if isValidis more clear thanif isValid == True, as it highlights exactly whatisValidis supposed to mean. I’m also going to take out the debug traces (printstatements that are clearly only there to check if the code’s doing the right thing; simplify the code first, and then there is less to check).Next, we’re going to simplify our conditional logic. First off, the result returned from
random.randint(0, z)cannot be< 0nor> z, ever, no matter what. That’s part of the very point of the function. So there is no point in writing code to handle those cases and in fact is wrong to do so. Writing code to handle something implies that it could actually happen. That’s a distraction for the person reading the code, and a lie, at that. It puts extra space between the things that matter (the call torandom.randintand the check against thepListvalue).We’re also going to simplify if/else pairs that simply set another boolean accordingly. For the same reason that you wouldn’t write
you shouldn’t do the same with booleans, either. Finally, we can and should use logical
andandorto connect boolean conditions.My next step will be to fix up the list indexing. Indexing into lists is usually not really what you want, and here in fact it introduces a bug. It’s evident that you want to iterate over each “row” of
pList; butrange(z)gives you numbers from0toz-1inclusive, so it’s incorrect to subtract 1 fromlen(pList)in calculatingz. For example, ifpListhas 5 elements, you will calculatez = 4, and producerange(z) = [0, 1, 2, 3]. You will never accesspList[4], andbwill only have 4 elements.You are doing two things with
z, fundamentally. One is to make a loop run as many times as there are “rows” inpList, and (in the first loop) do something with each “row”. To do thisThis is very important:
rangeis not magic, and it has no special connection to for-loops. It’s just a function that produces a list of numbers. In Python, aforloop gives you the elements directly. All this indexing nonsense is just that – nonsense, that is best left to less capable languages. If you want to do something with each element of a list, then do something with each element of the list, by writing code that loops over each element of the list. Directly. Not over some separate list of indices that you then use to index back into the original. That’s going out of your way to make things complicated.The second thing you do with
zis to generate a random number that’s a possible index, so that you can index intopListto get a random row. In other words, you just want to choose a random row. So just choose a random row. Therandommodule provides this functionality directly: the function is calledrandom.choice, and it does exactly what it sounds like.There’s one small hitch here: the original code compares
p == q, i.e. compares the two randomly chosen list indices for equality. If we’re no longer indexing, then we don’t have indices to compare. To fix this, we need to understand what the original purpose was: to check whether the new chosen row is actually the old chosen row again. Again, we simplify by checking that directly: we pick the new row instead of a new index, and then see if itisthe old one.We also have the problem that we need to choose a corresponding row from
bthat corresponds to whichever row inpListwe would previously have identified asq. To deal with that, we can select thebrow at the same time as thepListrow. This is a little tricky: my approach will be to make a list of pairs of rows – in each pair, there will be a row fromband then a row frompList. This doesn’t require anything complicated – there is in fact a built-in function that will stitchbandpListtogether exactly as we want: it’s calledzip. Anyway, having chosen a row-pair from that list of row-pairs, we just have to unpack the two rows into two variables – using theq, p = ...syntax that you were mistakenly using in the first place, as it turns out. That’s what it’s for.With these changes, we can actually get rid of
p,qandzentirely. Which is nice, because it’s not at all clear what those names were supposed to mean anyway.Time for a little more logical cleanup. In the first while loop, we will keep looping until
isValidbecomes true. That is to say, untilnot first_row[1]becomes true. In the second while loop,first_rownever gets changed, so, sincenot first_row[1]was true when the loop started, it will remain true the entire time. Therefore, that if-check is completely unnecessary.Once that’s gone, we find that the second while loop is actually also completely useless: it will loop
while not isMatch, i.e. untilisMatch. What isisMatch? Well, before we start the loop, it’sFalse, and at the end of the loop, it’sTrue. Always. So we know that this code will run exactly once. We enter the loop, go to the end, setisMatchto true, and then exit, sinceisMatch, having just been set to true, is true. Code that runs exactly once doesn’t need a loop; it’s just code.Another thing I’ll do here is to clean up the
while isValidloops a little bit by converting them to justbreakout when we’re done.breakis not evil (and neither iscontinue). They actually simplify our thinking about the booleans, because we aren’t checking againstnot isValidany more (emphasis on thenot); we’re just directly comparing to what we would have assigned toisValid. And this means we get rid of theisValidvariable, too, which again was a name that doesn’t actually tell us very much.One last thing: we can construct
bmuch more cleanly. Building up a list by appending elements is a sucker’s game. Don’t tell Python how to build lists. It knows how. Instead, ask for a list that meets your specifications, with a list comprehension. This is more simply shown than explained (if you need an explanation, please consult Google), so I’ll just go ahead and give you one more version:From here on, it’s hard to correct or improve anything without understanding what it is that you’re actually doing. After all this work, I still have no idea!
The way you have it set up, you choose a random row, as many times as there are rows – but you could still choose duplicates. Is that what you really want? Or did you want to choose each row once in a random order? What’s the significance of doing it in a random order, anyway?
After choosing the first row, you choose a random second row to match. Did you really want one random row per first row? Or did you want to try all possible pairs of rows?
And just what is all of this data, anyway? What does the output
bdata represent? What exactly is inpListto begin with, and why is it calledpList? What are you “matching” with thismatchfunction? I honestly can’t imagine.