【问题标题】:Auto updating class properties自动更新类属性
【发布时间】:2019-09-22 10:16:52
【问题描述】:

我正在构建一个knapsack 类,该类将Items(另一个类)列表作为参数。 每件物品都有重量和价值,一个背包应该有总重量(所有item.weights的总和)和总值(所有item.values的总和)。

我想要完成的是让knapsack.total_weightknapsack.total_value 在我knapsack.items.append(new_item) 时自动更新。

到目前为止,我已经尝试用@property 装饰itemstotal_weighttotal_value,但它似乎不起作用。关于如何正确使用属性装饰器的任何想法,或者我应该查看不同的实现?

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}'

【问题讨论】:

    标签: python list class oop python-descriptors


    【解决方案1】:

    您的想法是对的,但您似乎对 OOP 有点陌生。这样的事情怎么样?

    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')) 并破坏整个事情。

    【讨论】:

    • 这太棒了!谢谢你。我正在尝试更多地了解 OOP,并且只是认为从事遗传算法项目将是一个好的开始。再次感谢!
    【解决方案2】:

    您似乎没有有效地使用这些类。父类的子类会继承父类的属性。您可以使用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
    

    这样你就可以从你的父类创建你的物品并使用背包类的属性

    【讨论】:

    • 我不认为这正是我想要的。我希望能够在背包的总重量不超过最大重量的情况下向背包中添加新物品。我对课程比较陌生,所以我可能完全错了。
    • 这只是使用类的基本结构。要实现涉及最大权重的功能,只需使用if item =&gt; max_weight: do something else 之类的函数
    • 答案编辑为重量比较的例子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 2016-02-17
    • 2011-09-19
    • 2014-10-02
    • 2015-08-13
    • 1970-01-01
    相关资源
    最近更新 更多