代码之家  ›  专栏  ›  技术社区  ›  Ayub

正在从数据库中存储的列表中删除项:列表.删除(x) :x不在列表中

  •  1
  • Ayub  · 技术社区  · 5 年前

    我有一个 Message 班级:

    messages = []
    
    class Message:
       id = 1
       content = "m1"
    
       def __init__(self, id, content):
          self.id = id
          self.content = content
    

    以下代码按预期工作:

    m1 = Message(1, "m1")
    m2 = Message(2, "m2")
    
    messages.append(m1)
    messages.append(m2)
    messages.remove(m2) #Works as expected
    

    但当我加载 messages 从pickleDB并尝试删除该项时,会引发以下错误:

    def save_database():
       with open("database.db", 'wb') as f:
          pickle.dump(messages, f)
    
    def load_database():
       global messages
       with open("database.db", 'rb') as f:
          messages = pickle.load(f)
    
    def add_message(msg):
      load_database()
      messages.append(msg)
      save_database()
    
    
    m1 = Message(1, "m1")
    m2 = Message(2, "m2")
    
    add_message(m1)
    add_message(m2)
    
    load_database()
    messages.remove(m2) #ERROR: list.remove(x): x not in list
    
    1 回复  |  直到 5 年前
        1
  •  1
  •   costaparas    5 年前

    这是因为从pickle转储读取的对象与程序中的对象不同( pickle.load

    因此,当 remove 在列表中查找对象时,它将找不到该对象,而是引发异常。

    您需要通过实现自定义 __eq__ 方法 Message

    class Message:
    
        def __init__(self, id, content):
            self.id = id
            self.content = content
    
        def __eq__(self, other):
            if isinstance(other, Message):
                return self.id == other.id and self.content == other.content
            return False
    

    一般的方法是首先检查被比较的对象的类型是否正确。如果是,则比较相关字段。

    如果我不是这个班的老板,我该怎么办?

    您可以将其子类化,然后重写 __情商__ . 尽管在这种情况下,您可能需要考虑 super().__eq__ 表现也很好。

    完全覆盖eq的子类:

    在这个版本中,我们放弃了超类的 __情商__ 完全并实现我们自己的逻辑来检查相等性。

    class MyMessage(Message):
    
        def __init__(self, id, content, extra):
            super().__init__(id, content)
            self.extra = extra
    
        def __eq__(self, other):
            # As an example, we only check `extra`, and ignore everything else
            if isinstance(other, MyMessage):
                return self.extra == other.extra
            return False
    

    重写并考虑super()。\uu eq\uu的子类:

    在这个版本中,我们称之为超类的 __情商__ 再加上我们自己检查等式的逻辑。

    class MyMessage2(Message):
    
        def __init__(self, id, content, extra):
            super().__init__(id, content)
            self.extra = extra
    
        def __eq__(self, other):
            if isinstance(other, MyMessage2):
                ret = super().__eq__(other)
                if not ret:
                    return False
                return self.extra == other.extra
            return False