Python ValueError: слишком много значений для распаковки

Я получаю это исключение из этого кода:

class Transaction:
    def __init__ (self):
        self.materials = {}

    def add_material (self, m):
        self.materials[m.type + m.purity] = m

    def serialize (self):
        ser_str = 'transaction_start\n'

        for k, m in self.materials:
            ser_str += m.serialize ()

        sert += 'transaction_end\n'
        return ser_str

Строка for - это исключение. m являются объектами Material. У кого-нибудь есть идеи, почему?

Ответ 1

self.materials является dict, и по умолчанию вы выполняете итерацию только с помощью клавиш (которые являются строками).

Так как self.materials имеет более двух ключей *, они не могут быть распакованы в tuple "k, m", следовательно ValueError exception.

В Python 2.x, чтобы перебирать ключи и значения (tuple "k, m" ), мы используем self.materials.iteritems().

Однако, поскольку вы все равно выбрасываете ключ, вы можете просто перебирать значения словаря:

for m in self.materials.itervalues():

В Python 3.x предпочитаем dict.values() (который возвращает объект просмотра словаря):

for m in self.materials.values():

Ответ 2

for k, m in self.materials.items():

Пример:

miles_dict = {'Monday':1, 'Tuesday':2.3, 'Wednesday':3.5, 'Thursday':0.9}
for k, v in miles_dict.items():
    print("%s: %s" % (k, v))

Ответ 3

Итерация по самому объекту словаря фактически дает вам итератор по его ключам. Python пытается распаковать ключи, которые вы получаете от m.type + m.purity до (m, k).

Мой хрустальный шар говорит, что m.type и m.purity - обе строки, поэтому ваши клавиши также являются строками. Строки повторяемы, поэтому их можно распаковать; но итерация по строке дает вам итератор над его символами. Поэтому всякий раз, когда m.type + m.purity имеет длину более двух символов, у вас слишком много значений для распаковки. (И всякий раз, когда это короче, у вас слишком мало значений для распаковки.)

Чтобы исправить это, вы можете явно итератировать по items dict, которые являются парами (ключ, значение), которые вы, кажется, ожидаете. Но если вам нужны только значения, просто используйте значения.

(В 2.x, itervalues, iterkeys и iteritems, как правило, лучшая идея, а не iter версии создают новый объект списка, содержащий значения /keys/items. Для больших словарей и тривиальные задачи внутри итерации, это может быть намного медленнее, чем версии iter, которые просто устанавливают итератор.)