На второй вопрос
Понимания списка используются для создания другого списка в качестве вывода итерации по другому списку или спискам. Поскольку вы хотите запустить foo несколько раз, его более элегантно и менее запутанно использовать для цикла .. in range (..).
Если вы заинтересованы в сопоставлении возвращаемого значения foo, тогда вам следует использовать понимание списка, иначе для цикла это хорошо. По крайней мере, я бы так написал.
См. Пример ниже:
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def foo(): print 'foo'
...
>>>
>>> [foo() for x in range(10)]
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
[None, None, None, None, None, None, None, None, None, None]
>>>
[Редактировать: согласно запросу]
Версия iter, предоставленная eumiro.
>>> results = ( foo() for _ in xrange(10) )
>>> results
<generator object <genexpr> at 0x10041f960>
>>> list(results)
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
[None, None, None, None, None, None, None, None, None, None]
>>>