【问题标题】:.append() and .remove() not working in the same list - PYTHON - OOP.append() 和 .remove() 不在同一个列表中工作 - PYTHON - OOP
【发布时间】:2016-01-05 00:01:42
【问题描述】:

我对 python 有疑问。 我阅读了 2 本手册来学习这门语言(儿童 Python 和艰难学习 Python),现在我正试图了解 OOP 的工作原理以及如何使用它。

我想创建一个简单的脚本来学习如何处理类和方法:

脚本应该允许用户查看他在冰箱里有什么,每个物品都有一个数量和一个名称。用户应该能够做的其他事情是:添加项目、修改其名称或数量以及从“目录”中删除项目。

我尝试使用 OOP 设计来实现它,因为那是我想学习的。 问题是列表的 append() 和 remove() 方法的行为不同,即使被调用来处理同一个对象。

这是代码。我确信我在属性、参数和方法方面做错了,因为这是最让我困惑和让我对 OOP 感到疯狂的地方

class Item:
    def __init__(self, name, qty='1'):
        self.name = name
        self.qty = qty


class Fridge:
    def __init__(self):
        #create a Fridge object that is a list of stuff
        self.items = []
        #append to the list (fridge) an Item
    def add_item(self, name, qty='1'):
        self.items.append(Item(name))

    def modify_item(self):
        pass

    def remove_item(self,name, qty='0'):
        #from the items list remove Item(name))
        self.items.remove(Item(name))

当我在 shell 中使用 nameqty 参数调用 add_item 方法时,该函数实际上将项目添加到列表中。当我尝试删除 Item 它说:

Traceback (most recent call last):
  File "<pyshell#164>", line 1, in <module>
    f.remove_item('orange')
  File "C:/Users/Utente.1/Desktop/python projects/OOP/chap2 modules - packages/drill - frigorifero/fridge.py", line 22, in remove_item
    self.items.remove(Item(name))
ValueError: list.remove(x): x not in list

但是f.items[0].name 返回 'orange' 作为一个值。所以'orange' 存在并且存在,因为f.add_item('orange') 方法有效,但是当我使用f.remove_item('orange') 方法时我无法删除它。

怎么了?你能解释一下我的错误,还有你认为我缺少什么,而不是了解 OOP 以及如何改进它?在我看来,它就像一个迷宫。

【问题讨论】:

  • 为什么将数量存储为字符串?
  • 对设计的一个评论,我会尝试在概念上将项目定义和计数分开。我的意思是我会以某种方式定义项目,然后保留某种数据类型来跟踪其中有多少。例如,我会将项目存储为字典键,并使字典值对应于项目计数。通过这种方式,我们可以从项目的类型中获取有关有多少项目的数据。在这种情况下,我发现命名有点混乱,因为Item 具有项目的类型 有关同一类中有多少项目的信息...
  • ... 您可以将该行为封装到一个类中,并提供让您访问该类的方法,而无需将底层机制/机器暴露给您的类的最终用户。来自 Martijn Pieters 的 answer 为您提供了一个很好的建议,说明如何使用存储信息的基础列表来做到这一点。请记住,如果您的设计正确,您也可以将其更改为使用其他数据结构,而最终用户不知道他们正在使用您提供的 remove_item 等方法。
  • 你完全正确!这是我对 OOP 的第一次尝试,我真的很难理解事物并做出任何有意义的事情。所以我应该用字典替换列表?
  • 好吧,您也许可以这样做,但您不一定必须这样做。从 OOP 设计的角度来看,更大的问题是您尝试以这样一种方式编写代码,即如果您在内部更改为不同的数据结构,您的类代码的用户将不必知道更改。本质上,如果你做得正确,你可以改变你的实现,而最终用户不必更改他们的代码,这就是人们谈论封装时的意思。

标签: python class oop methods parameters


【解决方案1】:

您正在尝试从列表中删除 Item() 实例:

def remove_item(self,name, qty='0'):
    #from the items list remove Item(name))
    self.items.remove(Item(name))

如果没有额外的工作,这将无法工作; Item(name) 可能具有相同的名称,但它不等于列表中已有的任何对象。就 Python 而言,该对象是独立的,不会在列表中找到。

你有两个选择:

  • 手动搜索列表并删除具有匹配名称的一项。您可以通过过滤掉该项目的列表理解来做到这一点:

    self.items = [item for item in self.items if item.name != name]
    

    这实际上保留其他一切。

  • object.__eq__() method 添加到您的Item 类中,如果它们的名称相同,则声明两个项目相等:

    class Item:
        def __init__(self, name, qty='1'):
            self.name = name
            self.qty = qty
    
        def __eq__(self, other):
            if not isinstance(other, Item):
                return NotImplemented
            return self.name == other.name
    

    当与本身不是Item 实例的东西进行比较时,上述实现返回NotImplemented 标记对象;向 Python 发出信号以退回到默认行为,其中包括询问另一个对象是否等于这个对象。

【讨论】:

    【解决方案2】:

    您正在添加一个Item('orange'),然后您试图删除另一个Item('orange')。这是对Item() 类构造函数的两次调用,导致两个不同的实例。第一个在列表中,但第二个不在。

    您不能移除与您放在那里的不同的橙色。这是错误的原因。

    【讨论】:

    • 那么我如何设法删除项目列表中的项目?如何使 remove_item 方法起作用?
    • @user3722818:回答问题:在列表中搜索名称属性等于您要删除的内容的元素。但是,您还没有实现 qty 功能。为此,我将放弃使用列表的方法并改用 dict (key=name, value=quantity)。那么一个 remove_item 可能只是一个带有负数的 add_item(加上一些错误处理)。
    猜你喜欢
    • 2013-10-06
    • 1970-01-01
    • 2010-12-02
    • 2011-02-22
    • 2021-10-26
    • 1970-01-01
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多