问题是:
我实现了一个具有相当复杂的内部行为的类,它在所有意图和目的中都假装是int
类型。然后,作为最重要的一员,我真的希望我的类能够成功地通过int
的isinstance()和issubclass()检查。到目前为止我失败了。在
这是一个小的演示类,我用它来测试这个概念。我尝试从object
和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通常会使用基类raw value,而不是我精心设计的magic方法。不好的。在
我已经看过抽象基类,但它们似乎在做完全相反的事情:它们并没有使我的类看起来像一个内置类型的子类,而是让一个类假装成一个超类。在
使用__new__(cls, ...)
似乎也不是一个解决方案。如果你想要的只是在实际创建对象之前修改它的起始值,这是很好的,但是我想逃避不变性诅咒。尝试使用object.__new__()
也没有结果,因为Python只是抱怨使用object.__new__
来创建int
对象是不安全的。在
尝试从(int,dict)继承我的类并使用dict.__new__()
也不太成功,因为Python apperenty不允许在单个类中组合它们。在
我怀疑可以用元类找到解决方法,但到目前为止也没有成功使用元类,主要是因为我的大脑不够弯曲,无法正确理解它们。我还在努力,但看起来我不会很快就有结果的。在
所以,问题是:即使我的类是非常可变的,是否有可能继承或模仿不可变类型的继承?只要找到解决方案(假设它存在),类继承结构对我来说并不重要。在
到目前为止,还没有其他的解决方案被提出,所以下面是我最后使用的解决方案(大致基于Serge Ballesta的答案):
通过向
isinstance()
、issubclass()
和type()
调用提供可选的honest
参数,可以忽略伪造的继承。在使用示例。在
使类
^{pr2}$B
成为A
的假继承人:使类
B
假装是类A
:使类
B
和所有它的继承者假装为类A
:通过堆叠对
forge_inheritances()
的调用,可以实现多层假继承:显然,这种黑客攻击不会以任何方式影响}检查。在
super()
调用和属性/方法继承,这里的主要目的只是在无法直接修复的情况下欺骗isinstance()
和{这里的问题不是不变性,而是简单的继承。如果
DemoClass
是int的一个子类,则为DemoClass
类型的每个对象构造一个真的int
,并且将直接使用而不调用__int__
在任何可以使用int的地方,只要尝试a + 2
。在我宁愿在这里简单地作弊。我只需要使
object
的DemoClass
子类,并在自定义函数后面隐藏内置的isinstance
:然后我可以:
^{pr2}$所以,如果我理解正确,你有:
您需要调用}。在
i_want_int(DemoClass())
,其中DemoClass
可以通过__int__
方法转换为{如果要子类
int
,实例的值在创建时确定。在如果您不想在任何地方都编写对
^{pr2}$int
的转换(比如i_want_int(int(DemoClass()))
),那么我能想到的最简单的方法是为i_want_int
定义包装,执行转换:相关问题 更多 >
编程相关推荐