我有一个对象列表(Foo)。一个Foo对象有几个属性。一个Foo对象的实例与一个Foo对象的另一个实例等价(当且仅当)所有属性都相等。在
我有以下代码:
class Foo(object):
def __init__(self, myid):
self.myid=myid
def __eq__(self, other):
if isinstance(other, self.__class__):
print 'DEBUG: self:',self.__dict__
print 'DEBUG: other:',other.__dict__
return self.__dict__ == other.__dict__
else:
print 'DEBUG: ATTEMPT TO COMPARE DIFFERENT CLASSES:',self.__class__,'compared to:', other.__class__
return False
import copy
f1 = Foo(1)
f2 = Foo(2)
f3 = Foo(3)
f4 = Foo(4)
f5 = copy.deepcopy(f3) # overkill here (I know), but needed for my real code
f_list = [f1,f2,f3,f4,f5]
# Surely, there must be a better way? (this dosen't work BTW!)
new_foo_list = list(set(f_list))
我经常用这个(反?)”当处理简单类型(int、float、string)时,以及令人惊讶的日期时间。日期时间类型),但随着更复杂的数据类型(如上面的Foo)的出现,它变得越来越糟糕。在
那么,如何将上面的列表f1更改为一个唯一项的列表,而不必遍历每个项并检查它是否已经存在于某些临时缓存中等等?。在
什么是最Python式的方法?在
根据the documentation,您需要定义},以便自定义类正确使用},因为这两个都是使用CPython中的哈希表实现的。在
__hash__()
和{set
或{如果实现}必须等于
__hash__
,请记住如果a == b
,那么{hash(b)
。我建议为您的简单类提供以下更直接的实现,而不是比较整个__dict__
s:如果对象包含可变属性,则不应将其放在集合中或将其用作字典键。在
您是否尝试过使用
set
(或frozenset
)?它明确地用于保存一组唯一的项。在不过,您需要创建一个适当的
__hash__
方法。set
(和frozenset
)使用__hash__
方法散列对象;__eq__
只用于碰撞,AFAIK。相应地,您将希望使用类似hash(frozenset(self.__dict__.items()))
的散列。在首先,我想强调使用
set
当然不是反模式。set
s在O(n)时间内消除重复,这是您所能做的最好的方法,而且比将每个项目与其他项目进行比较的朴素的O(n^2)解决方案要好得多。它甚至比排序更好——事实上,似乎您的数据结构甚至可能没有一个自然的顺序,在这种情况下,排序没有多大意义。在在这种情况下使用集合的问题是必须定义一个自定义的
__hash__
方法。也有人这么说。但是你是否能轻松做到这一点是一个开放的问题——这取决于你的实际类的细节,你还没有告诉我们。例如,如果上面的Foo
对象的任何属性都是不可哈希的,那么创建一个自定义哈希函数将非常困难,因为您不仅要为Foo
对象编写自定义哈希,还必须为其他每种类型的对象编写自定义哈希!在所以如果你想要一个结论性的答案,你需要告诉我们更多关于你的类有什么样的属性。但我可以提供一些推测。在
假设可以为}(表示
Foo
对象编写散列函数,但也假设Foo
对象是可变的,因此,正如Niklas B.所指出的,这是一种可行的方法。创建一个函数freeze
,给定Foo
的可变实例,该函数返回Foo
中不可变的数据集合。例如,假设Foo中有一个dict
和一个list
;freeze
返回一个tuple
的tuple
(表示dict
)和另一个tuple
(表示dict
)和另一个{list
)。函数freeze
应具有以下属性:当且仅当
^{pr2}$现在通过以下代码传递您的列表:
现在你有了一个无重复的列表。(实际上,在添加了这个建议之后,我看到fraxel也提出了类似的建议;但是我认为使用自定义函数甚至是方法
(x.freeze(), x)
是更好的方法,而不是像他那样依赖__dict__
,这可能不可靠。您的自定义__eq__
方法也是如此,IMO--__dict__
并不总是一个安全的快捷方式,因为各种原因我无法进入这里。)另一种方法是首先只使用不可变的对象!例如,可以使用^{} s。下面是从python文档中窃取的一个示例:
相关问题 更多 >
编程相关推荐