如何覆盖 "set" 内置?
How to override "set" builtin?
我想实现以下功能:
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)
只有 obj1
和 obj3
在 test.values
我想知道如何以“协议”方式做到这一点,例如 len
或 add
等
def __len__(self):
return len(self.values)
与第一种方法相比,第二种方法是否具有有意义的好处?
如果您在 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)]
假设你的 value1
和 value2
是不可变的(整数、字符串和元组是好的;列表和字典不是),你可以散列它们——实现 __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)]))
...正确地 returns:
{NewClass(1, 2), NewClass(3, 4)}
只需添加这两个答案...使用冻结数据class 可以避免很多样板文件。它不仅为您生成 __hash__
、__eq__
和 __repr__
,而且还在对象的生命周期内强制执行不变性。
编写 __hash__
和 __eq__
在概念上并不难,但众所周知,它们很容易出错。更新 class 定义,例如添加或删除属性、更改属性数据类型等,可以为 class 属性和散列方法之间的差异留出空间。
这个问题对我来说是使用dataclasses的最大动力。您可以创建简洁、简单的不可变类型,您可以轻松对其进行哈希处理。您将列出或比较属性的繁琐工作留给了 dataclass 包装器,而只需要使用更易读的 class.
格式
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)}
我想实现以下功能:
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)
只有 obj1
和 obj3
在 test.values
我想知道如何以“协议”方式做到这一点,例如 len
或 add
等
def __len__(self):
return len(self.values)
与第一种方法相比,第二种方法是否具有有意义的好处?
如果您在 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)]
假设你的 value1
和 value2
是不可变的(整数、字符串和元组是好的;列表和字典不是),你可以散列它们——实现 __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)]))
...正确地 returns:
{NewClass(1, 2), NewClass(3, 4)}
只需添加这两个答案...使用冻结数据class 可以避免很多样板文件。它不仅为您生成 __hash__
、__eq__
和 __repr__
,而且还在对象的生命周期内强制执行不变性。
编写 __hash__
和 __eq__
在概念上并不难,但众所周知,它们很容易出错。更新 class 定义,例如添加或删除属性、更改属性数据类型等,可以为 class 属性和散列方法之间的差异留出空间。
这个问题对我来说是使用dataclasses的最大动力。您可以创建简洁、简单的不可变类型,您可以轻松对其进行哈希处理。您将列出或比较属性的繁琐工作留给了 dataclass 包装器,而只需要使用更易读的 class.
格式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)}