【发布时间】:2018-08-11 22:44:27
【问题描述】:
我想为实时 python 对象更改 isinstance 的行为。
一种解决方案是创建一个简单的包装器,如下所示,但我不喜欢它:
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
我不喜欢这个特殊的包装器,我们必须先从wlizard 中提取lizard,然后才能再次使用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 为wlizard 返回True,它为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
【问题讨论】:
-
这听起来像是你为某些潜在问题选择了一个糟糕的解决方案,如果不这样做的话会更好地解决。你为什么要以这种方式改变你的对象?为什么你关心你的对象如何响应
isinstance,而不是它们支持的行为? -
lizard是什么Python对象? -
@user2357112 我创建了一个包装器,它允许通过
__getattribute__访问对象的__getitem__方法。wrap_obj.key == obj[key]但是,我想知道返回的值是来自__getitem__还是obj的属性。一种解决方案似乎是在返回值上调用isinstance以查看它是什么。 -
@Blender 在我的示例中,
lizard是list。但是在实际应用中,我们不知道lizard会是什么先验的。解决方案需要足够通用以处理大多数类型的对象。 -
@ToothpickAnemone:既然您可以控制底层类,那么您要解决的具体问题是什么?这似乎是一个糟糕的方法。
标签: python python-3.x class inheritance metaclass