Trouble inserting in Python (None vs. empty list) - python

I'm trying to solve the following exercise from Google's Python class.
E. Given two lists sorted in increasing order, create and return a merged list of all the elements in sorted order. You may modify the passed in lists. Ideally, the solution should work in "linear" time, making a single pass of both lists.
I'm using the following Scheme approach (I wish I had car, cdr and cons!).
def helper(list1, list2, result):
if list1 == None:
return result + list2
elif list2 == None:
return result + list1
elif list1[0] < list2[0]:
return helper(list1[1:], list2, result.insert(0, list1[0]))
else:
return helper(list1, list2[1:], result.insert(0, list2[0]))
def linear_merge(list1, list2):
helper(list1, list2, [])
The error I get is, I can't seem to insert an element into result when result is []:
AttributeError: 'NoneType' object has no attribute 'insert'
But that works fine in the console:
>>> b = []
[]
>>> b.insert(0, 4)
>>> b
[4]
I'm brand new to Python, so I have two questions:
What am I missing about None vs. [], and how do I get this code to work?
If Python wasn't meant for a Scheme/Lisp approach, what's the "Python way" of solving this? This is less important to me, since I can just check the solutions.
Thanks!

list.insert returns None, not the modified list.
This requires helper to be changed to read
def helper(list1, list2, result):
if not list1:
return result + list2
elif not list2:
return result + list1
elif list1[0] < list2[0]:
return helper(list1[1:], list2, result + [list1[0]])
else:
return helper(list1, list2[1:], result + [list2[0]])
Note the changes to the two base cases. None and the empty list [] are not the same thing. The pythonic way of testing if a list is empty is to treat the list as a Boolean value: empty lists are False, all others are True.
And as the others have noticed before me, you need to explicitly return the return value of helper in linear_merge.

The first problem is that [] and None are not equal.
This causes two problems for you.
First, your test for the recursive base case isn't working. If you're trying to test for a list being empty, there are a number of ways to do it:
if not list1:
if list1 == []:
if len(list1) == 0:
But comparing it to None is not one of those ways.
The first is generally considered the most Pythonic (and explicitly encouraged by the PEP 8 style guide).
Second, you're apparently explicitly calling this function with None as an argument somewhere in code you haven't shown us. Don't do that. Call it with [] when you mean [].
And the other problem is that mutable methods like list.insert don't return the mutated object, they return None. So, instead of this:
return helper(list1[1:], list2, result.insert(0, list1[0]))
… you need to either do this:
result.insert(0, list1[0])
return helper(list1[1:], list2, result)
… or use a non-mutating expression instead:
return helper(list1[1:], list2, [list1[0]] + result)
And then, your linear_merge doesn't return anything, so its value will be None. Change it to:
return helper(list1, list2, [])

result.insert does not return a new list; it modifies an existing result in place. Thus you wind up passing None as the third argument to your nested helper() calls, because that's what result.insert returns - None.
Also note:
def linear_merge(list1, list2):
helper(list1, list2, [])
Since you don't return anything from linear_merge, you're always going to get None as the result.

Since you asked for a Pythonic solution, as well as how to fix your attempt, I'll write you one as a separate answer.
I'd do this by using iterators. At each step, you yielding the lower value and pulling the next one. The same way you'd do it in Haskell.* This actually is linear time, and it's lazy as well. Using more-itertools:
def itermerge(i1, i2):
i1, i2 = iter(i1), more_itertools.peekable(iter(i2))
for v1 in i1:
while i2 and i2.peek() < v1:
yield next(i2)
yield v1
yield from i2
If you need Python 2.x or 3.2 compatibility, just change the yield from i2 with for v2 in i2: yield v2.
If it's not clear how this works, here's the most explicit version, to show exactly what's happening at each step:
def itermerge(i1, i2):
i1, i2 = iter(i1), iter(i2)
sentinel = object()
v1, v2 = sentinel, sentinel
while True:
if v1 is sentinel:
try:
v1 = next(i1)
except StopIteration:
yield from i2
return
if v2 is sentinel:
try:
v2 = next(i2)
except StopIteration:
yield from i1
return
if v1 < v2:
yield v1
v1 = sentinel
else:
yield v2
v2 = sentinel
If you need a function that returns a list, that's easy:
def linear_merge(l1, l2):
return list(itermerge(l1, l2))
* This is a bit of a joke. While you can write pretty much any of the immutable versions of this algorithm in Haskell, the one that's most like this solution is probably not the one you'd write.

Related

Recursion- removes duplicates from the list

The question is to write a recursive function that Removes duplicates from the list.
Hint: it can be implemented with two auxiliary functions.
The list contains one and only one of each value formerly present
in the list. The first occurrence of each value is preserved.
Implement and test a recursive version of this method
def clean(self):
key_node = self._front
while key_node is not None:
# Loop through every node - compare each node with the rest
previous = key_node
current = key_node._next
while current is not None:
# Always search to the end of the list (may have > 1 duplicate)
if current._value == key_node._value:
# Remove the current node by connecting the node before it
# to the node after it.
previous._next = current._next
self._count -= 1
else:
previous = current
# Move to the _next node.
current = current._next
# Check for duplicates of the _next remaining node in the list
key_node = key_node._next
return
And this is what I have so far, I don't understand what is auxiliary functions:
def clean(list):
i = 1
if len(list) == 0:
return []
elif len(list) == 1:
return list
elif list[i] == list[i-1]:
del list[i]
return clean(list[i:])
Example: for list = [1,2,2,3,3,3,4,5,1,1,1], the answer is [1,2,3,4,5,1]
Here is one function that calls a another, recursive function and produces the result you want. I suppose you could call clean2 an auxiliary function, although, like you, I don't know exactly what that's supposed to mean. It's a rather ridiculous piece of code but it doesn't use any standard library functions and it modifies x in place. I would expect it to be horribly inefficient. If I wrote this for my day job I'd probably resign.
def clean(x):
clean2(x, 1)
def clean2(x, i):
if i >= len(x):
return
if x[i] == x[i - 1]:
del x[i]
clean2(x, i)
else:
clean2(x,i+1)
the_list = [1,2,2,3,3,3,4,5,1,1,1]
clean(the_list)
print(the_list)
>>> [1,2,3,4,5,1]
Here's a recursive definition using an auxiliary function go to actually implement the recursion. The idea is that the outer clean function can take any iterable object (e.g. a list) and it always produces a list of values:
def clean(iterable):
def go(iterator, result):
try:
x = next(iterator)
if result == [] or result[-1] != x:
result.append(x)
return go(iterator, result)
except StopIteration:
return result
return go(iter(iterable), [])
clean just invokes a locally-defined go function, passing an iterator and the eventual result value (initially an empty list). go then tries to advance the iterator and compares the referenced value with the end of the result: if it's different (or if the result is empty), the value is appended. go then recurses.

Summing nested lists in Python (not only int)

i got this task today from school to make a function Sum(list):
i researched and found out few ways how to make it work with list that consist of int, or list of list of integers, however my function should work also with other types like string, or tuples. Here are some examples of what it should do.
Sum([1,2,3]) returns 6; Sum([2,[1.5,3],0.5]) returns 7.0;
Sum([[['p'],'yt'],['h',['on']]]) returns 'python'
Sum([[(1,2)],(3,),[(4,5)]]) returns (1, 2, 3, 4, 5);
And on top of that all it should be also able to compute if argument in the function Sum(X) is NOT list. Example:
Sum(5*5) returns 25;
This is what i am working with so far, works fine for first 2 cases, however i cant find a way to modify it to work for other examples. Personaly ive been trying to use isinstance and exceptions
def list_sum(L):
total = 0
for i in L:
if isinstance(i, list):
total += list_sum(i)
else:
total += i
return total
Many thanks for any kind of help
Use the first non-list value as the initial value for the sum. Let None signify that we did not yet see such value:
def list_sum(L):
if not isinstance(L, list):
return L
total = None
for i in L:
i = list_sum(i)
if total is None:
total = i
else:
total += i
return total
Also, in this case, using isinstance is the sanest thing to do.
For the really robust case that handles empty lists correctly, make use of a flattening generator:
def list_sum(l):
def flatten(l):
for el in l:
if isinstance(el, list):
for sub in flatten(el):
yield sub
else:
yield el
if isinstance(l, list):
return sum(flatten(l))
return l
Note that the builtin sum function works in that case.
Here is a one-liner for doing this with just integers, for future reference:
from itertools import chain as flatten
def nested_sum(l):
return sum(flatten.from_iterable(l))
itertools.chain is great for flattening nested iterables.

recursively remove adjacent duplicates in a list

I looked up and found a close example, but the answer found in this link: Remove adjacent duplicate elements from a list won't run the test cases for this problem. So this is all I have so far:
def remove_dups(thelist):
"""Returns: a COPY of thelist with adjacent duplicates removed.
Example: for thelist = [1,2,2,3,3,3,4,5,1,1,1],
the answer is [1,2,3,4,5,1]
Precondition: thelist is a list of ints"""
i = 1
if len(thelist) == 0:
return []
elif len(thelist) == 1:
return thelist
elif thelist[i] == thelist[i-1]:
del thelist[i]
return remove_dups(thelist[i:])
def test_remove_dups():
assert_equals([], remove_dups([]))
assert_equals([3], remove_dups([3,3]))
assert_equals([4], remove_dups([4]))
assert_equals([5], remove_dups([5, 5]))
assert_equals([1,2,3,4,5,1], remove_dups([1,2,2,3,3,3,4,5,1,1,1]))
# test for whether the code is really returning a copy of the original list
mylist = [3]
assert_equals(False, mylist is remove_dups(mylist))
EDIT while I do understand that the accepted answer linked above using itertools.groupby would work, I think it wouldn't teach me what's wrong with my code & and would defeat the purpose of the exercise if I imported grouby from itertools.
from itertools import groupby
def remove_dups(lst):
return [k for k,items in groupby(lst)]
If you really want a recursive solution, I would suggest something like
def remove_dups(lst):
if lst:
firstval = lst[0]
# find lowest index of val != firstval
for index, value in enumerate(lst):
if value != firstval:
return [firstval] + remove_dups(lst[index:])
# no such value found
return [firstval]
else:
# empty list
return []
Your assertion fails, because in
return thelist
you are returning the same list, and not a copy as specified in the comments.
Try:
return thelist[:]
When using recursion with list it is most of the time a problem of returning a sub-list or part of that list. Which makes the termination case testing for an empty list. And then you have the two cases:
The current value is different from the last one we saw so we want to keep it
The current value is the same as the last one we saw so we discard it and keep iterating on the "rest" of the values.
Which translate in this code:
l = [1,2,2,3,3,3,4,5,1,1,1]
def dedup(values, uniq):
# The list of values is empty our work here is done
if not values:
return uniq
# We add a value in 'uniq' for two reasons:
# 1/ it is empty and we need to start somewhere
# 2/ it is different from the last value that was added
if not uniq or values[0] != uniq[-1]:
uniq.append(values.pop(0))
return dedup(values, uniq)
# We just added the exact same value so we remove it from 'values' and
# move to the next iteration
return dedup(values[1:], uniq)
print dedup(l, []) # output: [1, 2, 3, 4, 5, 1]
problem is with your return statement,
you are returning
return remove_dups(thelist[i:])
output will be always last n single element of list
like for above soon,
print remove_dups([1,2,2,3,3,3,4,5,1,1,1])
>>> [1] #as your desired is [1,2,3,4,5,1]
which returns finally a list of single element as it don't consider Oth element.
here is recursive solution.
def remove_dups(lst):
if len(lst)>1:
if lst[0] != lst[1]:
return [lst[0]] + remove_dups(lst[1:])
del lst[1]
return remove_dups(lst)
else:
return lst

tuple checking in python

i've written a small program:
def check(xrr):
""" goes through the list and returns True if the list
does not contain common pairs, IE ([a,b,c],[c,d,e]) = true
but ([a,b,c],[b,a,c]) = false, note the lists can be longer than 2 tuples"""
x = xrr[:]
#sorting the tuples
sorted(map(sorted,x))
for i in range(len(x)-1):
for j in range(len(x)-1):
if [x[i]] == [x[i+1]] and [x[j]] == [x[j+1]]:
return False
return True
But it doesnt seem to work right, this is probably something extremely basic, but after a couple of days trying on and off, i cant really seem to get my head around where the error is.
Thanx in advance
There are so many problems with your code as others have mentioned. I'll try to explain how I would implement this function.
It sounds like what you want to do is actually this: You generate a list of pairs from the input sequences and see if there are any duplicates among the pairs. When you formulate the problem like this it gets much easier to implement.
First we need to generate the pairs. It can be done in many ways, the one you would probably do is:
def pairs( seq ):
ret = []
# go to the 2nd last item of seq
for k in range(len(seq)-1):
# append a pair
ret.append((seq[k], seq[k+1]))
return ret
Now we want to see (a,b) and (b,a) and the same tuple, so we simply sort the tuples:
def sorted_pairs( seq ):
ret = []
for k in range(len(seq)-1):
x,y = (seq[k], seq[k+1])
if x <= y:
ret.append((x,y))
else:
ret.append((y,x))
return ret
Now solving the problem is pretty straight forward. We just need to generate all these tuples and add them to a set. Once we see a pair twice we are done:
def has_common_pairs( *seqs ):
""" checks if there are any common pairs among any of the seqs """
# store all the pairs we've seen
seen = set()
for seq in seqs:
# generate pairs for each seq in seqs
pair_seq = sorted_pairs(seq)
for pair in pair_seq:
# have we seen the pair before?
if pair in seen:
return True
seen.add(pair)
return False
Now the function you were trying to implement is quite simple:
def check(xxr):
return not has_common_pairs(*xxr)
PS: You can generalize the sorted_pairs function to work on any kind of iterable, not only those that support indexing. For completeness sake I'll paste it below, but you don't really need it here and it' harder to understand:
def sorted_pairs( seq ):
""" yield pairs (fst, snd) generated from seq
where fst <= snd for all fst, snd"""
it = iter(seq)
fst = next(it)
for snd in it:
if first <= snd:
yield fst, snd
else:
yield snd, fst
first = snd
I would recommend using a set for this:
def check(xrr):
s = set()
for t in xrr:
u = tuple(sorted(t))
if u in s:
return False
s.add(u)
return True
This way, you don't need to sort the whole list and you stop when the first duplicate is found.
There are several errors in your code. One is that sorted returns a new list, and you just drop the return value. Another one is that you have two nested loops over your data where you would need only one. Here is the code that makes your approach work:
def check(xrr):
x = sorted(map(sorted,xrr))
for i in range(len(x)-1):
if x[i] == x[i+1]:
return False
return True
This could be shortened to
def check(xrr):
x = sorted(map(sorted,xrr))
return all(a != b for a, b in zip(x[:-1], x[1:]))
But note that the first code I gave will be more efficient.
BTW, a list in Python is [1, 2, 3], while a tuple is (1, 2, 3).
sorted doesn't alter the source, it returns a new list.
def check(xrr):
xrrs = map(sorted, xrr)
for i in range(len(xrrs)):
if xrrs[i] in xrrs[i+1:]: return False
return True
I'm not sure that's what's being asked, but if I understood it correctly, I'd write:
def check(lst):
return any(not set(seq).issubset(lst[0]) for seq in lst[1:])
print check([(1, 2, 3), (2, 3, 5)]) # True
print check([(1, 2, 3), (3, 2, 1)]) # False
Here is more general solution, note that it find duplicates, not 'non-duplicates', it's better this way and than to use not.
def has_duplicates(seq):
seen = set()
for item in seq:
if hasattr(item, '__iter__'):
item = tuple(sorted(item))
if item in seen:
return True
seen.add(item)
return False
This is more general solution for finding duplicates:
def get_duplicates(seq):
seen = set()
duplicates = set()
for item in seq:
item = tuple(sorted(item))
if item in seen:
duplicates.add(item)
else:
seen.add(item)
return duplicates
Also it is better to find duplicates, not the 'not duplicates', it saves a lot of confusion. You're better of using general and readable solution, than one-purpose functions.

Searching values of a list in another List using Python

I'm a trying to find a sublist of a list. Meaning if list1 say [1,5] is in list2 say [1,4,3,5,6] than it should return True. What I have so far is this:
for nums in l1:
if nums in l2:
return True
else:
return False
This would be true but I'm trying to return True only if list1 is in list2 in the respective order. So if list2 is [5,2,3,4,1], it should return False. I was thinking along the lines of comparing the index values of list1 using < but I'm not sure.
try:
last_found = -1
for num in L1:
last_found = L2.index(num, last_found + 1)
return True
except ValueError:
return False
The index method of list L2 returns the position at which the first argument (num) is found in the list; called, like here, with a second arg, it starts looking in the list at that position. If index does not find what it's looking for, it raises a ValueError exception.
So, this code uses this approach to look for each item num of L1, in order, inside L2. The first time it needs to start looking from position 0; each following time, it needs to start looking from the position just after the last one where it found the previous item, i.e. last_found + 1 (so at the start we must set last_found = -1 to start looking from position 0 the first time).
If every item in L1 is found this way (i.e. it's found in L2 after the position where the previous item was found), then the two lists meet the given condition and the code returns True. If any item of L1 is ever not-found, the code catches the resulting ValueError exception and just returns False.
A different approach would be to use iterators over the two lists, that can be formed with the iter built-in function. You can "advance" an iterator by calling built-in next on it; this will raise StopIteration if there is no "next item", i.e., the iterator is exhausted. You can also use for on the iterator for a somewhat smoother interface, where applicable. The low-level approach using the iter/next idea:
i1 = iter(L1)
i2 = iter(L2)
while True:
try:
lookfor = next(i1)
except StopIteration:
# no more items to look for == all good!
return True
while True:
try:
maybe = next(i2)
except StopIteration:
# item lookfor never matched == nope!
return False
if maybe == lookfor:
break
or, a bit higher-level:
i1 = iter(L1)
i2 = iter(L2)
for lookfor in i1:
for maybe in i2:
if maybe == lookfor:
break
else:
# item lookfor never matched == nope!
return False
# no more items to look for == all good!
return True
In fact, the only crucial use of iter here is to get i2 -- having the inner loop as for maybe in i2 guarantees the inner loop won't start looking from the beginning every time, but, rather, it will keep looking where it last left off. The outer loop might as well for for lookfor in L1:, since it has no "restarting" issue.
Key, here, is the else: clause of loops, which triggers if, and only if, the loop was not interrupted by break but rather exited naturally.
Working further on this idea we are again reminded of the in operator, which also can be made to continue where it last left off simply by using an iterator. Big simplification:
i2 = iter(L2)
for lookfor in L1:
if lookfor not in i2:
return False
# no more items to look for == all good!
return True
But now we recognize that is exactly the patter abstracted by the short-circuiting any and all built-in "short-circuiting accumulator" functions, so...:
i2 = iter(L2)
return all(lookfor in i2 for lookfor in L1)
which I believe is just about as simple as you can get. The only non-elementary bit left here is: you need to use an iter(L2) explicitly, just once, to make sure the in operator (intrinsically an inner loop) doesn't restart the search from the beginning but rather continues each time from where it last left off.
This question looks a bit like homework and for this reason I'd like to take the time and discuss what may be going wrong with the snippet shown in the question.
Although you are using a word in its plural form, for the nums variable, you need to understand that Python will use this variable to store ONE item from l1 at a time, and go through the block of code in this "for block", one time for each different item.
The result of your current snippet will therefore be to exit upon the very first iteration, with either True or False depending if by chance the first items in the list happen to match.
Edit: Yes, A1, exactly as you said: the logic exits with True after the first iteration. This is because of the "return" when nums is found in l2.
If you were to do nothing in the "found" case, the loop the logic would proceed with finishing whatever logic in the block (none here) and it would then start the next iteration. Therefore it would only exit with a "False" return value, in the case when an item from l1 is not found l2 (indeed after the very first such not-found item). Therefore your logic is almost correct (if it were to do nothing in the "found case"), the one thing missing would be to return "True", systematically after the for loop (since if it didn't exit with a False value within the loop, then all items of l2 are in l1...).
There are two ways to modify the code so it does nothing for the "found case".
- by using pass, which is a convenient way to instruct Python to do nothing; "pass" is typically used when "something", i.e. some action is syntactically required but we don't want anything done, but it can also be used when debugging etc.
- by rewriting the test as a "not in" instead
if nums not in l2:
return False
#no else:, i.e. do nothing at all if found
Now... Getting into more details.
There may be a flaw in your program (with the suggested changes), that is that it would consider l1 to be a sublist of l2, even if l1 had say 2 items with value say 5 whereby l2 only had one such value. I'm not sure if that kind of consideration is part of the problem (possibly the understanding is that both lists are "sets", with no possible duplicate items). If duplicates were allowed however, you would have to complicate the logic somewhat (a possible approach would be to intitially make a copy of l2 and each time "nums" is find in the l2 copy, to remove this item.
Another consideration is that maybe a list can only be said to be a sublist if its items are found the same order as the items in the other list... Again it all depends on the way the problem is defined... BTW some of the solutions proposed, like Alex Martelli's are written in such fashion because they solve the problem in a way that the order of items with the lists matter.
I think this solution is the fastest, since it iterates only once, albeit on the longer list and exits before finishing the iteration if a match is found. (Edit: However, it is not as succinct or as fast as Alex's latest solution)
def ck(l1,l2):
i,j = 0,len(l1)
for e in l2:
if e == l1[i]:
i += 1
if i == j:
return True
return False
An improvement was suggested by Anurag Uniyal (see comment) and is reflected in the showdown below.
Here are some speed results for a range of list size ratios (List l1 is a 10-element list containing random values from 1-10. List l2 ranges from 10-1000 in length (and also contain random values from 1-10).
Code that compares run times and plots the results:
import random
import os
import pylab
import timeit
def paul(l1,l2):
i = 0
j = len(l1)
try:
for e in l2:
if e == l1[i]:
i += 1
except IndexError: # thanks Anurag
return True
return False
def jed(list1, list2):
try:
for num in list1:
list2 = list2[list2.index(num):]
except: return False
else: return True
def alex(L1,L2): # wow!
i2 = iter(L2)
return all(lookfor in i2 for lookfor in L1)
from itertools import dropwhile
from operator import ne
from functools import partial
def thc4k_andrea(l1, l2):
it = iter(l2)
try:
for e in l1:
dropwhile(partial(ne, e), it).next()
return True
except StopIteration:
return False
ct = 100
ss = range(10,1000,100)
nms = 'paul alex jed thc4k_andrea'.split()
ls = dict.fromkeys(nms)
for nm in nms:
ls[nm] = []
setup = 'import test_sublist as x'
for s in ss:
l1 = [random.randint(1,10) for i in range(10)]
l2 = [random.randint(1,10) for i in range(s)]
for nm in nms:
stmt = 'x.'+nm+'(%s,%s)'%(str(l1),str(l2))
t = timeit.Timer(setup=setup, stmt=stmt).timeit(ct)
ls[nm].append( t )
pylab.clf()
for nm in nms:
print len(ss), len(ls[nm])
pylab.plot(ss,ls[nm],label=nm)
pylab.legend(loc=0)
pylab.xlabel('length of l2')
pylab.ylabel('time')
pylab.savefig('cmp_lsts.png')
os.startfile('cmp_lsts.png')
results:
This should be easy to understand and avoid corner case nicely as you don't need to work with indexes:
def compare(l1, l2):
it = iter(l2)
for e in l1:
try:
while it.next() != e: pass
except StopIteration: return False
return True
it tries to compare each element of l1 to the next element in l2.
if there is no next element (StopIteration) it returns false (it visited the whole l2 and didn't find the current e) else it found it, so it returns true.
For faster execution it may help to put the try block outside the for:
def compare(l1, l2):
it = iter(l2)
try:
for e in l1:
while it.next() != e: pass
except StopIteration: return False
return True
I have a hard time seeing questions like this and not wishing that Python's list handling was more like Haskell's. This seems a much more straightforward solution than anything I could come up with in Python:
contains_inorder :: Eq a => [a] -> [a] -> Bool
contains_inorder [] _ = True
contains_inorder _ [] = False
contains_inorder (x:xs) (y:ys) | x == y = contains_inorder xs ys
| otherwise = contains_inorder (x:xs) ys
The ultra-optimized version of Andrea's solution:
from itertools import dropwhile
from operator import ne
from functools import partial
def compare(l1, l2):
it = iter(l2)
try:
for e in l1:
dropwhile(partial(ne, e), it).next()
return True
except StopIteration:
return False
This can be written even more functional style:
def compare(l1,l2):
it = iter(l2)
# any( True for .. ) because any([0]) is False, which we don't want here
return all( any(True for _ in dropwhile(partial(ne, e), it)) for e in l1 )
I have a feeling this is more intensive than Alex's answer, but here was my first thought:
def test(list1, list2):
try:
for num in list1:
list2 = list2[list2.index(num):]
except: return False
else: return True
Edit: Just tried it. His is faster. It's close.
Edit 2: Moved try/except out of the loop (this is why others should look at your code). Thanks, gnibbler.

Categories

Resources