我想实现以下功能:
TestClass
values
接受任意数量的NewClass
对象- 只有不具有所有相同属性值的
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
中只有obj1
和obj3
我想知道如何在";协议";方式,如len
或add
等
def __len__(self):
return len(self.values)
与第一种方法相比,第二种方法有意义的好处吗?
假设您的value1
和value2
是不可变的(整数、字符串和元组都可以;列表和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)]