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!在接受之前会等待一段时间-也许会提供一个不那么粗鲁的答案。情况有点复杂