Python 创建/模拟不可变内置类型的可变子类

Python 创建/模拟不可变内置类型的可变子类,python,metaclass,Python,Metaclass,问题是: 我实现了一个具有相当复杂内部行为的类,该类在所有意图和目的下都假装为int类型。然后,作为顶部的一个樱桃,我真的希望我的类能够成功地通过isinstance()和issubclass()检查int。到目前为止我失败了 这里有一个小的演示类,我用它来测试这个概念。我已经尝试从对象和int继承它,从int继承它使它通过检查,同时也破坏了它的一些行为: #class DemoClass(int): class DemoClass(object): _value = 0 def

问题是:

我实现了一个具有相当复杂内部行为的类,该类在所有意图和目的下都假装为
int
类型。然后,作为顶部的一个樱桃,我真的希望我的类能够成功地通过isinstance()和issubclass()检查
int
。到目前为止我失败了

这里有一个小的演示类,我用它来测试这个概念。我已经尝试从
对象
int
继承它,从
int
继承它使它通过检查,同时也破坏了它的一些行为:

#class DemoClass(int):
class DemoClass(object):
    _value = 0
    def __init__(self, value = 0):
        print 'init() called'
        self._value = value
    def __int__(self):
        print 'int() called'
        return self._value + 2
    def __index__(self):
        print 'index() called'
        return self._value + 2
    def __str__(self):
        print 'str() called'
        return str(self._value + 2)
    def __repr__(self):
        print 'repr() called'
        return '%s(%d)' % (type(self).__name__, self._value)
    # overrides for other magic methods skipped as irrelevant

a = DemoClass(3)

print a         # uses __str__() in both cases
print int(a)    # uses __int__() in both cases
print '%d' % a  # __int__() is only called when inheriting from object

rng = range(10)
print rng[a]    # __index__() is only called when inheriting from object

print isinstance(a, int)
print issubclass(DemoClass, int)
本质上,从一个不可变类继承会产生一个不可变类,Python通常会使用基类原始值,而不是我精心设计的神奇方法。不太好

我已经研究过抽象基类,但它们似乎做了完全相反的事情:它们没有使我的类看起来像内置类型的子类,而是使一个类假装成一个类的超类

使用
\uuuu new\uuuu(cls,…)
似乎也不是一个解决方案。如果您只想在实际创建对象之前修改对象的起始值,这是很好的,但我想避开不变性诅咒。尝试使用
对象。
也没有结果,因为Python只是抱怨使用
对象不安全。
创建
int
对象

尝试从(int,dict)继承我的类并使用
dict.\uuu new\uuuu()
也不是很成功,因为Python显然不允许将它们组合到一个类中

我怀疑元类可以找到解决方案,但到目前为止,元类也没有成功,主要是因为我的大脑没有足够的弯曲来正确理解它们。我仍在努力,但看起来不会很快有结果


所以,问题是:即使我的类是非常可变的,也有可能从不可变类型继承或模仿继承吗?只要找到解决方案(假设它存在),类继承结构对我来说并不重要。

这里的问题不是不变性,而只是继承。如果
DemoClass
是int的一个子类,则会为
DemoClass
类型的每个对象构造一个真正的
int
,并将直接使用,而无需调用
\uuuu int\uuuu
,只要尝试
a+2

我宁愿在这里简单地作弊
isinstance
。我只需创建
DemoClass
对象的子类
object
,并将内置的
isinstance
隐藏在自定义函数后面:

class DemoClass(object):
    ...

def isinstance(obj, cls):
    if __builtins__.isinstance(obj, DemoClass) and issubclass(int, cls):
        return True
    else:
        return __builtins__.isinstance(obj, cls)
我可以这样做:

>a=DemoClass(3)
调用了init()
>>>isinstance(“abc”,str)
真的
>>>isinstance(a,演示类)
真的
>>>isinstance(a,int)
真的
>>>issubclass(DemoClass,int)
假的

因此,如果我理解正确,您有:

def i_want_int(int_):
    # can't read the code; it uses isinstance(int_, int)
您需要调用
i\u-want\u-int(DemoClass())
,其中
DemoClass
可通过
\uu-int
方法转换为
int

如果您想要子类化
int
,实例的值将在创建时确定

如果您不想在任何地方都编写到
int
的转换(如
i\u-want\u-int(int(DemoClass())
),我可以考虑的最简单的方法是为
i\u-want\u-int
定义包装器,执行转换:

def i_want_something_intlike(intlike):
    return i_want_int(int(intlike))

到目前为止,还没有提出其他解决方案,因此我最后使用的解决方案是(大致基于Serge Ballesta的回答):

可以通过向
isinstance()
issubclass()
type()
调用提供可选的
omnity
参数来忽略伪造的继承

用法示例

使阶级
B
成为阶级
a
的假继承人:

class A(object): pass
class B(object): pass
forge_inheritances(disguise_heir = { B: A })
b = B()
print isinstance(b, A) # prints True
print isinstance(b, A, honest = True) # prints False
class A(object): pass
class B(object): pass
forge_inheritances(disguise_type = { B: A})
b = B()
print type(b) # prints "<class '__main__.A'>"
print type(b, honest = True) # prints "<class '__main__.B'>"
class A(object): pass
class B(object): pass
class D(B): pass
forge_inheritances(disguise_tree = { B: A})
d = D()
print type(d) # prints "<class '__main__.A'>"
让班级
B
假装成为班级
A

class A(object): pass
class B(object): pass
forge_inheritances(disguise_heir = { B: A })
b = B()
print isinstance(b, A) # prints True
print isinstance(b, A, honest = True) # prints False
class A(object): pass
class B(object): pass
forge_inheritances(disguise_type = { B: A})
b = B()
print type(b) # prints "<class '__main__.A'>"
print type(b, honest = True) # prints "<class '__main__.B'>"
class A(object): pass
class B(object): pass
class D(B): pass
forge_inheritances(disguise_tree = { B: A})
d = D()
print type(d) # prints "<class '__main__.A'>"
通过堆叠对
forge\u inheritances()
的调用,可以实现多层伪继承:


显然,这种攻击不会以任何方式影响
super()
调用和属性/方法继承,这里的主要目的只是在无法直接修复它们的情况下欺骗
isinstance()
type(inst)=class
检查。

您试图实现什么?当类的实例本身是
int
s时,为什么需要
\u value
属性?@GingerPlusPlus,这是一个示例类,不是我正在使用的真实类。当然,我正在努力实现一些额外的兼容性。我处理的是我无法更改甚至无法看到的第三方代码,我想向它传递一些数据,其中一些
int
值被替换为伪int类的实例,这是获得一些炫酷特性所必需的。如果在第三方代码中发生检查,至少
isinstance()
检查会成功,这将是非常好的,因为它减少了我必须要求其他人做的更改量。那么你不需要
\u值
,因为
isinstance(self,int)
。您可以简单地执行
super(),而不是执行
self.\u value+anything
。这是一个示例类。Real类实际上使用的是dict,它使用外部单例类中定义的许多动态变化的规则转换为整数值-您真的想在问题文本中看到所有这些吗?我提供了最简单的示例,
\u value+2
仅用于提供动态评估。我没有想到要取代内置的iInstance,但它确实有效!这是一个非常棘手的解决方案,但情况也是如此,我已经在更换
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!在接受之前会等待一段时间-也许会提供一个不那么粗鲁的答案。情况有点复杂