从 pickleDB 中的存储列表中删除项目会抛出:list.remove(x): x not in list

Removing item from a stored list in pickleDB throws: list.remove(x): x not in list

我有一个 Message class:

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

但是当我从 pickleDB 加载 messages 并尝试删除该项目时,它会抛出此错误:

list.remove(x): x not in list

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

那是因为从 pickle dump 中读取的对象与您程序中的对象不同(pickle.load() 创建了新对象)。

因此,当 list.remove() 查找列表中的对象时,它不会找到它而是引发异常。

另请参阅 this post,其中讨论了默认情况下如何在 Python 中定义对象的相等性。

您需要通过在 Message class:

中实施自定义 __eq__ 方法来覆盖检查相等性的方式
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

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

如果我不拥有 class,我该如何处理?

您可以子 class 它,然后覆盖 __eq__。尽管在这种情况下,您可能还需要考虑 super().__eq__ 的行为方式。

完全覆盖 __eq__ 的子class:

在这个版本中,我们完全放弃了 superclass 的 __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

Subclass 覆盖并考虑 super().__eq__:

在这个版本中,我们调用了 superclass 的 __eq__ 并添加了我们自己的逻辑来检查相等性。

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