объединение двух словарей по умолчанию

Я пытаюсь создать объединение двух словарей по умолчанию. Вот код метода в моем классе:

def __add__(self,right):
    mergedbag = copy.copy(self.bag_value)
    for item in right:
        if item not in mergedbag:mergedbag[item] = 0
        mergedbag[item] += right[item]
    return mergedbag

Я создаю два словаря по умолчанию:

b = Bag(['d','a','b','d','c','b','d'])
c = Bag(['d','a','b','d','c','b','d'])

результат

print(b+c)

должно быть общее количество элементов после объединения..

Bag(a[a],b[4],c[3],d[6])

Это ошибка, которую я продолжаю получать:

    Traceback (most recent call last):
  File "D:\workspace33\courselib\driver.py", line 229, in driver

Command[print(b+c)]:     exec(old,local,globl)
  File "<string>", line 1, in <module>
  File "D:\workspace33\Project2\src\bag.py", line 58, in __add__
    mergedbag[item] += right[item]
TypeError: 'Bag' object is not subscriptable

Вот новый код:

class Bag:
def __init__(self, items = []):
    self.bag_value = defaultdict(int)
    for item in items:
        self.bag_value[item] += 1


def __repr__(self):
    bag_list = []
    for item, count in self.bag_value.items():
        bag_list.extend(list(item*count))
    return 'Bag(' + str(bag_list) + ')'



def __str__(self):
    return 'Bag(' + ','.join(str(item) + '[' + str(count) + ']' for item, count in self.bag_value.items()) + ')'



def __len__(self):
    bag_len = 0
    for value in self.bag_value:
        bag_len += self.bag_value[value]
    return bag_len



def unique(self):
    return len(self.bag_value)




def __contains__(self, item):
    return item in self.bag_value



def count(self, item):
    return(self.bag_items.count(item))



def add(self, new):
    self.bag_value[new] += 1



def __add__(self,right):
    mergedbag = copy.copy(self.bag_value)
    for item in right:
        if item not in mergedbag:mergedbag[item] = 0
        mergedbag[item] += right[item]
    return mergedbag



def remove(self, item):
    if item in self.bag_items:
        del(item)
    else:
        raise ValueError(type_as_str(item) + ' not in bag.')



def __eq__(self, right):
    if type(right) is not Bag:
        raise TypeError('Cannot compare Bag with' + type_as_str(right) + '. Can only compare Bag with Bag')
    else:
        return (len(self) == len(right)) and  (self.unique() == right.unique())



def __ne__(self, right):
    return not self.__eq__(right)



def _bag_gen(self, bag_value):
    for item in self.bag_value:
        for count in range(self.bag_value[item]):
            yield item



def __iter__(self):
    return self._bag_gen(self.bag_value)



if __name__ == '__main__':
#     bag = Bag(['d','a','b','d','c','b','d'])
#     bag2 = Bag(['d','a','b','d','c','b','d'])
#     bag3 = Bag(['d','a','b','d','c','b'])
#     print(bag == bag2)
#     print(bag == bag3)
#     print(bag != bag2)
#     print(bag != bag3)
    import driver
    driver.driver()

person BoJaNgLeS    schedule 26.01.2015    source источник
comment
Что такое Bag и что вы подразумеваете под Is there a way to make the method accept command str(Bag(['a','b] + Bag(['b','c']))?   -  person Jon Clements♦    schedule 26.01.2015
comment
Bag['a', 'b] отсутствует ' - Bag['a', 'b']. Если после этого все еще возникает ошибка, было бы полезно, если бы вы могли опубликовать полную трассировку, а также больше вашего класса Bag.   -  person lvc    schedule 26.01.2015
comment
@Ivc - только что опубликовал класс   -  person BoJaNgLeS    schedule 26.01.2015
comment
Нам также нужно видеть точную ошибку, которую вы получаете, а не просто синтаксическую ошибку.   -  person lvc    schedule 27.01.2015
comment
У меня есть несколько рекомендаций по этому коду: 1. Я склоняюсь к наследованию bag от defaultdict(int), поэтому вам не нужно реализовывать много методов как len(). 2. Попробуйте использовать больше iteritems() вместо items(). 3. Старайтесь не использовать параметры по умолчанию для таких объектов, как items=[], так как эти объекты повторно используются при вызовах функций. Не уверен, что здесь проблема, но я бы рекомендовал использовать items=None   -  person drodri    schedule 27.01.2015
comment
@drodri- другие методы независимы и используются для проверки других вещей, таких как длина сумки, уникальные предметы в сумке и так далее.   -  person BoJaNgLeS    schedule 27.01.2015
comment
@Ivc - я добавил код ошибки.   -  person BoJaNgLeS    schedule 27.01.2015
comment
Что указывает именно на недостающую цитату, которую я предложил в своем первом комментарии. Исправление этого должно решить насущную проблему... голосование за закрытие как опечатку.   -  person lvc    schedule 27.01.2015
comment
@drodri вопрос помечен [python-3.x], где dict.items больше не создает список. Кроме того, вы не можете наследовать defaultdict(it), только defaultdict. Но вы можете получить тот же эффект, унаследовав dict и определив __missing__ для возврата 0, что и делает collections.Counter.   -  person lvc    schedule 27.01.2015
comment
@drodri, Ivc .. Я обновил вопрос. Извини за это.   -  person BoJaNgLeS    schedule 27.01.2015
comment
Упс, извините за 3.x, не видел. Я знаю, что другие методы являются вспомогательными, но лучше их убрать и свести к минимуму возможность воспроизведения проблемы. Я все еще вижу некоторые проблемы: __ init __ получает предметы, которые на самом деле не назначены bag_items (это что-то особенное в 3.x?). Метод __ add __ по-прежнему получает 2 параметра, как говорит @st0le, подпись должна быть __ add __(self, other), это еще не исправлено.   -  person drodri    schedule 28.01.2015
comment
@drodri - я также внес изменения в __init__, чтобы выполнить назначение для bag_items.   -  person BoJaNgLeS    schedule 28.01.2015


Ответы (2)


Прежде всего, важно отметить, что ваш класс Bag в основном такой же, как Counter. Если вам нужно какое-то конкретное расширение, просто наследуйте его, и все готово. Я бы сказал, что следующий код просто обращается ко всем функциям, которые вы сами реализуете в своем классе Bag:

from collections import Counter

class Bag(Counter):
    pass

b = Bag(['d','a','b','d','c','b','d'])
c = Bag(['d','a','b','d','c','b','d'])

print (b)
print (c)
print (b+c)

Если вы выполняете упражнение для обучения, проблема заключается в том, что вы не реализуете методы setitem и getitem в своем классе Bag, чтобы разрешить нотацию []. Вы можете реализовать их или просто получить доступ к атрибуту bag_value:

def __add__(self, right):
    mergedbag = Bag()
    mergedbag.bag_value = copy.copy(self.bag_value)
    for item in right.bag_value.keys():
        mergedbag.bag_value[item] += right.bag_value[item]
    return mergedbag

Обязательно создайте и верните объект Bag

person drodri    schedule 29.01.2015

Определение

def __add__(self,other):

Таким образом, вы должны объединить содержимое self.items с other.items, а затем вернуть результат.

Кроме того, не уверен, что bag1+bag2 будет работать, но мой pyfu слаб, вам придется явно перебирать их и складывать счетчики вместе.

import copy

c = {'a':2,'b':1}
d = {'b':1,'c':1}

#
mergedBag = copy.copy(c) #might wanna use deepcopy?
for k in d:
    if k not in mergedBag: mergedBag[k] = 0
    mergedBag[k] += d[k]

print mergedBag
person st0le    schedule 26.01.2015
comment
@ st0le .. Я обновил вопрос. Извини за это. - person BoJaNgLeS; 27.01.2015
comment
@BoJaNgLeS, привет, как объяснено в моем ответе, dict1+dict2 не будет работать. Вам придется перебирать каждый ключ и создавать новый объединенный словарь. Я добавил код выше. - person st0le; 28.01.2015
comment
@ st0le- я попробовал это, и это дает мне ошибку объекта, не подлежащую подписке. Я обновил код. - person BoJaNgLeS; 29.01.2015