Python “如何覆盖”;“设置”;内置的?

Python “如何覆盖”;“设置”;内置的?,python,set,overriding,built-in,Python,Set,Overriding,Built In,我想实现以下功能: TestClass值接受任意数量的NewClass对象 只有不具有所有相同属性值的NewClass对象才会添加到 TestClass.values 我想到了这个: class NewClass: def __init__(self, value1, value2): self.value1 = value1 self.value2 = value2 class TestClass: def __init__(self,

我想实现以下功能:

  • TestClass
    接受任意数量的
    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
    测试中。值

    我想知道如何以“协议”的方式来做,例如
    len
    add

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

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

    如果在
    NewClass
    上定义
    \uuuuuu hash\uuuuu
    \uuuuuu eq\uuuuu
    ,则可以将实例传递给
    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
    是不可变的(整数、字符串和元组是可以的;列表和dict不是),您可以对它们进行散列处理——实现
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuu散列和
    \uuuuuuuuuuuuuuuueq\uuuuuuuuuuu
    将允许内置集类型识别重复项

    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)}
    

    只是为了补充这两个答案。。。使用冻结的数据类可以避免大量的样板文件。它不仅为您生成
    \uuuuuuuhash\uuuuuu
    \uuuuueq\uuuuu
    \uuuuurepr\uuuuu
    ,而且还强制对象在生命周期内保持不变

    从概念上讲,编写
    \uuuuuuuuuuuuuhash\uuuuuuu
    \uuuuuuueq\uuuuuuuu
    并不难,但众所周知,它们很容易出错。对类定义的更新(如添加或删除属性、更改属性数据类型等)会为类属性和哈希方法之间的差异留出空间

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

    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)
    

    “设置内置”是指数据类型
    set
    ?否则,就存在
    \uuuu setattr\uuuuu
    \uuuuu setitem\uuuuuuuuu
    ,但我不知道任何只是
    设置的东西。是的,我应该把链接放在问题中以避免歧义。。。无论如何,我认为实现这一点的“协议方式”是覆盖哈希机制。谢谢你的回答,所以
    \u set
    方法很好?顺便说一句,当你的新类真的这么简单时,考虑使用
    collections.namedtuple
    ,它将“免费”给你这个属性。这就是我想要的,关于
    value1
    value2
    的可变性,我认为值得在这里提及数据类。像
    @dataclass(freezed=True)
    一样,它将为您处理这个样板文件。我自己做了一个回答来强调这一点。@flakes,谢谢您——Python已经好几年没有成为我的主要语言了;当我全职编写时,最接近的是
    集合。命名为tuple
    ,因此从更熟悉现代库的人那里得到完整的答案有很多好处。@CharlesDuffy绝对值得研究一下数据类和类型提示注释。如今,他们让人觉得这是一种完全不同的语言非常有用的关于易变性的警告。肯定是一个必要的补充,涵盖了可能的陷阱,以及一个很好的解释。
    {NewClass(value1=1, value2=2), NewClass(value1=5, value2=2)}