【问题标题】:Deep Copy of Lists of Custom Objects自定义对象列表的深层副本
【发布时间】:2013-04-09 13:40:13
【问题描述】:

假设我有一个应用程序列表,描述为自定义对象。我决定对原始应用程序列表进行深度复制,这样我就可以拥有一个充当可用应用程序池的列表。为了分配应用程序,我随机选择池的一个子集,然后在原始列表中找到这些应用程序,以便我可以更新它们的信息。然后,从池中删除分配的应用程序。但是,由于某种原因,这些应用程序永远无法在原始列表中找到:

list1 = [App1,App2,App3,App4,App5]
pool = copy.deepcopy(list1)
num_apps = rand.randrange(0,5)
random.shuffle(pool)
selected_apps = copy.deepcopy(pool[:num_apps])
for app in selected_apps:
    locn = list1.index(app)
    print locn

上面的代码实际上会返回一个 ValueError ,表示在 selected_apps 中找不到一个项目。错误是因为我正在制作包含非 Python 原生对象的列表的深层副本,还是其他原因?

【问题讨论】:

  • 您是否为您的 App 类实现了 __eq__ 方法?很可能发生的情况是 .index 方法无法比较两个相同的 App 对象,因为您已经完成了深层复制并且它们的内存地址已经改变。
  • 啊,我还没有尝试实现__eq__ 方法。我去看看,谢谢!

标签: python list deep-copy


【解决方案1】:

当使用list.index时,它使用比较运算符(==)来检查项目是否相同,然后使用__eq__方法,from documentation

用户自定义类默认有__eq__()__hash__()方法;使用它们,所有对象都比较不相等(除了它们自己)x.__hash__() 返回一个适当的值,使得x == y 暗示x is yhash(x) == hash(y)

您可以通过以下方式证明这一点:

>>> class A(object):
...     def __init__(self):
...         self.x = 0
... 
>>> a = A()
>>> a.x = 5
>>> b = a
>>> b == a
True
>>> c = copy.deepcopy(a)
>>> c == a
False

在CPython中id()返回一个对象的内存地址,所以__eq__在id匹配时返回true:

>>> id(a) 
140389541757224
>>> id(b)
140389541757224
>>> id(c)
140389541757336

所以你只需要实现__eq__方法和__ne__

比较运算符之间没有隐含的关系。 x==y 的真实性并不意味着x!=y 是虚假的。因此,在定义__eq__() 时,还应定义__ne__(),以便运算符按预期运行。

>>> class A(object):
...     def __init__(self):
...         self.x = 0
...     def __eq__(self, o):
...         return self.x == o.x
...     def __ne__(self, o):
...         return self.x != o.x
... 
>>> a = A()
>>> a.x = 5
>>> b = a
>>> c = copy.deepcopy(a)
>>> d = A()
>>> d.x = 4
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a == d
False

还要注意这一点:

如果一个类没有定义__eq__() 方法,它也不应该定义__hash__() 操作;如果它定义了__eq__() 而不是__hash__(),它的实例将不能用作可散列集合中的项目

【讨论】:

    猜你喜欢
    • 2018-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 2015-12-28
    相关资源
    最近更新 更多