Создайте список различных пустых изменяемых файлов
Мне нужно инициализировать список defaultdicts. Если бы они были, скажем, струнами, это было бы аккуратно:
list_of_dds = [string] * n
... но для изменчивых, вы попадаете в беспорядок с таким подходом:
>>> x=[defaultdict(list)] * 3
>>> x[0]['foo'] = 'bar'
>>> x
[defaultdict(<type 'list'>, {'foo': 'bar'}), defaultdict(<type 'list'>, {'foo': 'bar'}), defaultdict(<type 'list'>, {'foo': 'bar'})]
То, что я действительно хочу, является итерируемым из недавно отчеканенных отдельных случаев defaultdicts. Я могу сделать это:
list_of_dds = [defaultdict(list) for i in xrange(n)]
но я чувствую себя немного грязным, используя здесь понимание списка. Я думаю, что есть лучший подход. Есть? Пожалуйста, скажи мне, что это.
Редактировать:
Вот почему я чувствую, что понимание списка неоптимально. Обычно я не являюсь типом предварительной оптимизации, но я не могу игнорировать разницу в скорости:
>>> timeit('x=[string.letters]*100', setup='import string')
0.9318461418151855
>>> timeit('x=[string.letters for i in xrange(100)]', setup='import string')
12.606678009033203
>>> timeit('x=[[]]*100')
0.890861988067627
>>> timeit('x=[[] for i in xrange(100)]')
9.716886043548584
2 ответа
Ваш подход, использующий понимание списка, верен. Почему вы думаете, что это грязно? То, что вы хотите, это список вещей, длина которых определяется некоторым базовым набором. Постижения списков создают списки на основе некоторого базового набора. Что не так с использованием здесь понимания списка?
Изменить: Разница в скорости является прямым следствием того, что вы пытаетесь сделать. [[]]*100
быстрее, потому что он должен создать только один список. Создание нового списка каждый раз медленнее, да, но вы должны ожидать, что он будет медленнее, если вы действительно хотите 100 разных списков.
(Он не создает новую строку каждый раз в ваших примерах строк, но он все еще медленнее, потому что понимание списка не может "знать" заранее, что все элементы будут одинаковыми, поэтому ему все равно придется переоценивать выражение каждый раз. Я не знаю внутренних деталей списка компоновки, но возможно, есть также некоторые накладные расходы на изменение размера списка, потому что он не обязательно знает размер итеративного индекса, с которого можно начать, поэтому он может • предварительно распределяйте список. Кроме того, обратите внимание, что некоторое замедление в вашем примере строки связано с поиском string.letters
на каждой итерации. На моей системе используется timeit.timeit('x=[letters for i in xrange(100)]', setup='from string import letters')
вместо --- глядя вверх string.letters
только один раз - сокращает время примерно на 30%.)
Понимание списка - это именно то, что вы должны использовать.
Проблема с умножением списка состоит в том, что создается список, содержащий один изменяемый объект, а затем вы пытаетесь продублировать его. Но, пытаясь продублировать объект из самого объекта, код, используемый для его создания, больше не актуален. Ничто из того, что вы делаете с объектом, не будет делать то, что вы хотите, то есть запускать код, использованный для его создания, N раз, потому что объект не знает, какой код использовался для его создания.
Вы можете использовать copy.copy или copy.deepcopy для его дублирования, но это вернет вас обратно в ту же самую лодку, потому что тогда вызов copy / deepcopy просто станет кодом, который вам нужно выполнить N раз.
Понимание списка здесь очень хорошо подходит. Что с этим не так?