如何覆盖内置"set"?



我想实现以下功能:

  1. TestClassvalues接受任意数量的NewClass对象
  2. 只有不具有所有相同属性值的NewClass对象才会被添加到TestClass.values

我想出了这个:

class NewClass:
def __init__(self, value1, value2):
self.value1 = value1
self.value2 = value2

class TestClass:
def __init__(self, *values):
self.values = self._set(values)
def _set(self, object_list):
unique_dict = {}
for obj in object_list:
if list(obj.__dict__.values()) not in unique_dict.values():
unique_dict[obj] = list(obj.__dict__.values())
return list(unique_dict.keys())

obj1 = NewClass(1, 2)
obj2 = NewClass(1, 2)
obj3 = NewClass(5, 2)
test = TestClass(obj1, obj2, obj3)

test.values中只有obj1obj3

我想知道如何在";协议";方式,如lenadd

def __len__(self):
return len(self.values)

与第一种方法相比,第二种方法有意义的好处吗?

假设您的value1value2是不可变的(整数、字符串和元组都可以;列表和dict则不然(,您可以对它们进行哈希处理——同时实现__hash____eq__将允许内置的集合类型识别重复项。

class NewClass:
def __init__(self, value1, value2):
self.value1 = value1
self.value2 = value2
def __hash__(self):
return hash((self.value1, self.value2))
def __eq__(self, other):
return self.value1 == other.value1 and self.value2 == other.value2
def __repr__(self):
return 'NewClass(%r, %r)' % (self.value1, self.value2)
print(set([NewClass(1,2), NewClass(1,2), NewClass(3,4)]))

正确返回:

{NewClass(1, 2), NewClass(3, 4)}

只需添加到这两个答案中。。。使用冻结的数据类可以避免很多样板文件。它不仅为您生成__hash____eq____repr__,而且在对象的生存期内强制执行不变性。

编写__hash____eq__在概念上并不难,但众所周知,它们很容易出错。对类定义的更新,如添加或删除属性、更改属性数据类型等,可以为类属性和哈希方法之间的差异留出空间。

对我来说,这个问题是使用数据类的最大动机。您创建了简洁、简单的不可变类型,可以轻松地对其进行散列。将列出或比较属性的繁琐工作留给数据类包装器,只需使用更易于阅读的类格式即可。

from dataclasses import dataclass
@dataclass(frozen=True)
class NewClass:
value1: int
value2: int
obj1 = NewClass(1, 2)
obj2 = NewClass(1, 2)
obj3 = NewClass(5, 2)
test = {obj1, obj2, obj3}
print(test)
{NewClass(value1=1, value2=2), NewClass(value1=5, value2=2)}

如果在NewClass上定义__hash____eq__,则可以将实例传递给set(),它将使用这些函数来确定对象在集合方面是否相等。对于可变实例,您需要小心,因为属性可能会在事后发生更改。

这里有一个简单的例子:

class NewClass:
def __init__(self, value1, value2):
self.value1 = value1
self.value2 = value2
def __hash__(self):
# take the hash of the tuple
return hash((self.value1, self.value2))
def __eq__(self,other):
# are the tuples equal?
return (self.value1, self.value2) == (other.value1, other.value2)
def __repr__(self):
return f'NewClass({self.value1}, {self.value2})'
class TestClass:
def __init__(self, *values):
self.values = list(set(values))

obj1 = NewClass(1, 2)
obj2 = NewClass(1, 2)
obj3 = NewClass(5, 2)
test = TestClass(obj1, obj2, obj3)
test.values
# Only the different instances:
# [NewClass(1, 2), NewClass(5, 2)]

最新更新