Автообновление свойств класса - PullRequest
1 голос
/ 22 сентября 2019

Я создаю класс knapsack, который принимает список Items (другой класс) в качестве параметра.У каждого предмета есть вес и значение, а у рюкзака должен быть общий вес (сумма всех item.weights) и общая стоимость (сумма всех item.values).

Я пытаюсь сделать так, чтобы knapsack.total_weight и knapsack.total_value обновлялись автоматически, когда я knapsack.items.append(new_item).

До сих пор я пытался украсить items, total_weight и total_value с @property, но, похоже, это не сработало.Любые идеи о том, как правильно использовать декораторы свойств или я должен смотреть на другую реализацию?

class Item:
    def __init__(self,name:str,weight:int,value:int):
        self.name = name
        self.weight = weight
        self.value = value

    def __str__(self):
        return f'{self.name}: {self.weight}kg ({self.value})'

class Knapsack:

    def __init__(self,items=[],max_weight=250,score=None,weight=None):
        self.max_weight = max_weight
        self._items = items
        self._score = score
        self._weight = weight

    @property
    def items(self):
        return self._items

    @items.setter
    def items(self,new_item):
        self._items += [new_item]
        self._score = self._items
        self._weight = self._items

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self,items):
        total_score = 0
        for item in items:
            total_score += item.value
        self._score = total_score

    @property
    def weight(self):
        return self._weight

    @weight.setter
    def weight(self,items):
        total_weight = 0
        for item in items:
            total_weight += item.weight
        self._weight = total_weight

    def __str__(self):
        out = [item.name for item in self.items]
        return f'{"".join(out)}\t{self.score}'

Ответы [ 2 ]

1 голос
/ 23 сентября 2019

У вас правильная идея, но вы, кажется, немного новичок в ООП.Как на счет этого?

class Item:
    def __init__(self, name, value, weight):
        self.name = name
        self.value = value
        self.weight = weight


class Knapsack:
    def __init__(self, max_weight):
        self._items = []
        self.max_weight = max_weight

    @property
    def total_weight(self):
        return sum(i.weight for i in self._items)

    @property
    def total_value(self):
        return sum(i.value for i in self._items)

    def add(self, item):
        if self.total_weight + item.weight > self.max_weight:
            raise ValueError("that ain't gonna fit in there")
        self._items.append(item)

sack = Knapsack(100)
sack.add(Item('a', 1, 10))
sack.add(Item('b', 1, 20))
sack.add(Item('c', 1, 30))

print('Total weight: ', sack.total_weight)
print('Total value: ', sack.total_value)

try:
    sack.add(Item('too big', 1, 50))
except ValueError as e:
    print(e)

Обновление:

Несколько заметок.Вы можете реализовать средство установки элементов так, как вы это делали, но конечное использование будет нелогичным, вам нужно будет сделать что-то вроде sack.items = item, чтобы добавить элемент.Вы не хотите определять сеттеры ни для веса, ни для значения, поскольку они изменяются только при изменении элементов и не могут быть изменены независимо.Вы можете попытаться сделать Knapsack подклассом списка, но вам придется реализовать кучу «секретных» методов, чтобы заставить его работать, и я думаю, что для новичка это слишком сложно для небольшой выгоды.

Обновление при обновлении:

Имейте в виду, что вышеупомянутое не является высококачественной треской, она предназначена только для иллюстрации реализации.Например, я бы сделал sack.add(Item('x', 'x', 'x')) и сломал бы все это.

0 голосов
/ 22 сентября 2019

Не похоже, что вы используете классы эффективно.Подкласс родительского класса будет наследовать атрибуты от родительского класса.Вы можете изменить их или добавить атрибуты с помощью метода super().__init__.Например, с выводом:

class Item:
    def __init__(self, name, weight, value):
        self.name = name
        self.weight = weight
        self.value = value


item = Item('Random_Item', 0, 0)
print('Name: {} \nWeight: {} \nValue: {} '.format(item.name, item.weight, item.value))


class Knapsack(Item):
    def __init__(self, max_weight, score):
        self.max_weight = max_weight
        self.score = score
        super().__init__('A_different_random_item', weight=0, value=0)


knapsack = Knapsack(250, None)
print('Name: {} \nMax Weight: {} \nScore: {} \nValue: {}'.format(knapsack.name, knapsack.max_weight, knapsack.score, knapsack.value))

Это дает вывод:

Name: Random_Item 
Weight: 0 
Value: 0
Name: A_different_random_item 
Max Weight: 250 
Score: None 
Value: 0

РЕДАКТИРОВАНИЕ ДЛЯ ДОБАВЛЕНИЯ В КОММЕНТАРИИ

heavy_stone = Item('Wood', weight=251, value=20)

choice = input('Put stone in knapsack: ')
if choice.lower() == 'y' and heavy_stone.weight < 250:
    pass ### ADD ITEM ###
else:
    print('Sorry that weighs {} and is too heavy for your knapsack. It can only hold {}'.format(heavy_stone.weight, knapsack.max_weight))

Выход:

Put stone in knapsack: y
Sorry that weighs 251 and is too heavy for your knapsack. It can only hold 250

Таким образом, вы можете создавать свои предметы из родительского класса и использовать атрибуты из класса ранца

...