【问题标题】:When Class Inherits from built-in List当类从内置列表继承时
【发布时间】:2015-11-14 16:58:59
【问题描述】:

我声明了三个MyClass 实例。我想将这些实例中的每一个存储在列表变量instances 中。在 instance 附加到 instances 之前,我仔细检查它是否已经在列表中。有趣的是,这三个实例似乎与 Python 完全相同。为什么会发生这种情况?我们应该知道什么才能避免将来发生此类意外?

instances=[]
for i in range(3):
    instance=MyClass(i)
    for each in instances:
        if each==instance:
            print 'THE SAME?', each.ID,'==', instance.ID
    if instance not in instances:
        print "Instance %s is not in instances"%instance.ID
        instances.append(instance)
    else:
        print "Instance %s is already in instances"%instance.ID 
        index=instances.index(instance)
        instanceFromList=instances[index]
        print "COMPARE: instance.ID:", instance.ID, '   instanceFromList.ID:', instanceFromList.ID  

print 'Number of instances stored:', len(instances)

输出:

Instance 0 is not in instances
THE SAME? 0 == 1
Instance 1 is already in instances
COMPARE: instance.ID: 1    instanceFromList.ID: 0
THE SAME? 0 == 2
Instance 2 is already in instances
COMPARE: instance.ID: 2    instanceFromList.ID: 0

Number of instances stored: 1

【问题讨论】:

  • in 运算符检查 identity 然后 equality,在这种情况下它们是相等的。定义您的自定义 __eq____ne__ 方法。使用方法:PyObject_RichCompareBool
  • 刚刚编辑了我的示例以使用== 运算符进行检查。它也会误导......
  • @Sputnix 为什么会产生误导?这就是列表的行为方式。两个空列表相等。它不会使用您添加的任意属性,除非您自己覆盖相等测试并告诉它这样做。

标签: python list class inheritance


【解决方案1】:

因为列表是空的,所以它们比较相等。这是因为用于确定每个实例是否在“实例”列表中的比较是值比较,而不是身份比较

如果您要在将 ID=1 的 MyClass 实例添加到“实例”列表之前添加一些内容,那么您的代码也会添加 ID=2 的空 MyClass 实例。

不使用列表子类型的示例:

>>> a = list()
>>> b = list()
>>> a == b  # equal value
True
>>> a is b
False  # different identity
>>> c = list()
>>> c.append(a)
>>> a in c
True
>>> b in c
True
>>> a.append("a value")
>>> a == b  # now the values differ
False
>>> a in c  # The value of 'a' changed, and 'a' is still in 'c'
True
>>> b in c  # 'b' is still empty, and there's no empty list in 'c'
False

要支持基于 ID 实例变量的“MyClass in list”比较,您必须在您的类中实现 __eq____ne__ 比较方法。然后这些方法应该比较实例的类型和它们的 ID。

请注意,如果您实现了这一点,您还将失去比较 MyClass 实例内容的能力。

【讨论】:

  • 感谢您的澄清!
【解决方案2】:

我不确定您为什么希望它的行为与常规列表不同:

instances = []
for i in range(3):
    instance = []
    if instance not in instances:
        print 'Adding instance to list...'
        instances.append(instance)
    else:
        print 'Instance is already present in list'
        print instances

print 'Number of instances stored:', len(instances)

打印出来:

Adding instance to list...
Instance is already present in list
[[]]
Instance is already present in list
[[]]
Number of instances stored: 1

如果您希望它通过考虑您给它的 id 以某种方式区分您的 list 子类,您必须通过 overriding how your object responds to equality tests 自己定义该行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多