在进行二进制操作时,如何使Python `set`和`frozenset`子类保留其类型?

在进行二进制操作时,如何使Python `set`和`frozenset`子类保留其类型?,python,types,immutability,subclassing,binary-operators,Python,Types,Immutability,Subclassing,Binary Operators,我有一些set和frozenset子类,OCDSet和OCDFrozenSet。当我在二进制操作中将它们与它们的祖先类的实例一起使用时,祖先类控制着结果的类型——我的意思是,当我从冻结集中减去OCDFrozenSet时,我得到一个frozenset…但如果我在操作中反转类型(即从OCDFrozenSet中减去frozenset),情况也是如此 像这样: …让我特别不安的是,使用-=(就地减法)会改变现有实例的类型 我如何处理这种事情的知识严格地来自C++,其中的操作类型是在一个(可能模板化)中

我有一些
set
frozenset
子类,
OCDSet
OCDFrozenSet
。当我在二进制操作中将它们与它们的祖先类的实例一起使用时,祖先类控制着结果的类型——我的意思是,当我从
冻结集
中减去
OCDFrozenSet
时,我得到一个
frozenset
…但如果我在操作中反转类型(即从
OCDFrozenSet
中减去
frozenset
),情况也是如此

像这样:

…让我特别不安的是,使用
-=
(就地减法)会改变现有实例的类型

我如何处理这种事情的知识严格地来自C++,其中的操作类型是在一个(可能模板化)中明确指定的一个放弃的结论。运算符重载函数;在Python中,类型系统通常更隐式,但它并不像我现在相信的就地操作那样易变不可预测


那么,解决这个问题最方便的方法是什么呢?我假设它涉及重写感兴趣的子类中的一些双下划线实例方法。

就地操作并不保证它们会就地更新对象,它完全取决于对象的类型

Tuple、frozenset等是不可变的类型,因此不可能就地更新它们

从现场操作员开始:

对于字符串、数字和元组等不可变目标,将计算更新后的值,但不会将其分配回输入变量

类似地,
frozenset
文档也提到了同样的事情[]:

下表列出了不适用于frozenset不可变实例的集合可用操作


现在,由于您的
OCDFrozenSet
没有实现
\uuuuiSub\uUuUn
,它将回退到
\uUuSub\uUuUn
方法,该方法将返回基类
frozenset
的类型。之所以使用基类,是因为Python不知道您的基类从
\uuuuu sub\uuuuu
操作

更重要的是,这是一个这样的操作返回子类实例的地方,修复只是为了防止破坏现有系统


要获得预期的输出,您可以在子类中提供所需的方法:

class OCDFrozenSet(frozenset):
    def __sub__(self, other):
        return type(self)(super().__sub__(other))

    def __rsub__(self, other):
        return type(self)(super().__rsub__(other))

好的,哇,谢谢!-虽然(如果我错了,请纠正我)我看到的行为(使用就地运算符的实例类型发生变化)不是意味着更新后的值实际上被分配回输入变量,与引用相反吗?而且,您的回答暗示我可能要实现
\uiSub__(…)
在可变子类上–是这样吗?@fish2000输入变量,是的,但它不再是同一个对象,即
id()
将不同,并且对该对象的其他引用也不会受到影响。它只是一个分配给变量的全新对象。请检查:。是的,
\uuiSub\uUu
适用于您的情况。