我想改变isinstance
的行为python对象的行为。
一种解决方案是创建一个简单的包装器,如下所示,但我不喜欢它:
class Widget:
def __init__(self, obj):
self.inner_self = obj
lizard = ['head', 'nose', 'tail']
wlizard = Widget(lizard)
assert(isinstance(wlizard, Widget)) # no assertion error thrown
我不喜欢这个特殊的包装,是我们必须从lizard
中提取wlizard
才能再次使用lizard
try:
wlizard[0]
except:
print('sorry, wlizard doesn\'t behave like a lizard')
lizard = wlizard.inner_self
print(lizard[0]) # works fine
我真正想要的是wlizard
表现得像蜥蜴,除了isinstance
为True
返回wlizard
并且它为lizard
返回false。
以下类型的工作,但有一些缺点:
class Widget:
pass
def MakeAWidget(obj):
class Blah(type(obj), Widget):
pass
# inherits type(obj)'s __init__ method
wobj = Blah(obj) # calls type(obj)'s copy constructor
return wobj
一个问题是,只有当type(obj)
的__init__()
方法不仅仅需要self
时,这才有效;特别是,__init__
可以接受type(obj)
的一个实例,当它确实时,它将obj
的属性复制到self
。即使obj
没有复制构造函数,我也想要一些有用的东西。类似下面的内容可能会强制存在复制构造函数:
import copy
class Blah(type(obj), Widget):
def __init__(*args, **kwargs):
if isinstance(args[0], type(obj)):
self = copy.deepcopy(args[0])
return self
return super(type(self), self).__init__(*args, **kwargs)
但是,我宁愿不复制对象,只能就地修改它。可能有类似下面的内容,但我不确定__BLAH__
会是什么:
obj = ['apple', 'pear', 'banana']
assert(not isinstance(obj, Widget)) # no error thrown
obj.__BLAH__.append('Widget')
assert(isinstance(obj, Widget)) # no error thrown
这是我认为你想要的东西。 wrap()
函数动态创建一个类,该类派生自传递给它的obj
参数的类,然后返回从中创建的该类的实例。这假设obj
类支持复制构造(从相同或派生类的实例初始化)。
def wrap(obj):
class MetaClass(type):
def __new__(mcls, classname, bases, classdict):
wrapped_classname = '_%s_%s' % ('Wrapped', type(obj).__name__)
return type.__new__(mcls, wrapped_classname, (type(obj),)+bases, classdict)
class Wrapped(metaclass=MetaClass):
pass
return Wrapped(obj)
lizard = ['head', 'nose', 'tail']
wlizard = wrap(lizard)
print(type(wlizard).__name__) # -> _Wrapped_list
print(isinstance(wlizard, list)) # -> True
try:
wlizard[0]
except Exception as exc:
print(exc)
print("sorry, wlizard doesn't behave like lizard")
else:
print('wlizard[0] worked')