我使用的是一个包,它给了我一个对象,里面装满了一堆数据,我不想费心手动序列化这些数据并用来初始化另一个对象。我想做的是为我自己的目的在对象上附加一堆额外的方法。在
理想情况下,我希望神奇地将实例子类化,但这似乎不可能。Monkey-patching可能“有用”,但互联网上说这不是什么好形式,因为我的代码的其他部分实际上可能会在其他地方使用本机类,这看起来很危险。在
我尝试创建一个包装器对象,但是很多(全部?),所以它是不完整的。处理一堆传递函数定义(例如def __iter__(self): return iter(object.__getattribute__(self, '_digraph'))
)似乎很笨拙(我可能会忘记一个)。在
class ColliderGraph(object):
def __init__(self, digraph):
self._digraph = digraph
def __getattribute__(self, name):
cls_attrs = ['_digraph', 'whereis', 'copy'] # more to follow.
if name not in cls_attrs:
return object.__getattribute__(
object.__getattribute__(self, '_digraph'), name)
else:
return object.__getattribute__(self, name)
#return getattr(self._digraph, name)
def whereis(self, node):
"""find a node inside other nodes of the digraph"""
def copy(self):
return ColliderGraph(self._digraph.copy())
在另一个更有限的地方,我开始使用一个单数函数patch the instance,如下所示:
^{pr2}$但是如果调用.copy()
,那么它就失去了升级(我想我也可以修补它……),并且以这种方式添加一堆方法似乎很难看,但也许是可行的。在
有更好的出路吗?在
首先,我认为最明智的选择是修补
digraph
实例以添加所需的方法,并在其中包含修补__copy__
,或者甚至坚持使用包装,并使用元类为魔术方法添加代理,如this answer中对您链接的问题的建议。在这就是说,我最近在玩弄“神奇地”将一个实例子类化的想法,并认为我应该与您分享我的发现,因为您在玩同样的事情。下面是我想出的代码:
其思想是重新定义实例的
^{pr2}$__class__
,将其更改为我们选择的新类,并将__class__
的原始值添加到inst.__bases__
(以及新类型的__bases__
)。另外,我们将新类型的__dict__
复制到实例中。这听起来相当疯狂,也许是,但在我用它做的一点测试中,它似乎(大部分)实际起作用:输出:
除了最后一行-
isinstance(m, MagicThread)
是False
之外,所有的输出都与我们想要的完全一样。这是因为我们实际上没有将__class__
分配给我们定义的MagicMethod
类。相反,我们创建了一个具有相同名称和所有相同方法/属性的单独的类。理想情况下,这可以通过在retype_instance
内重新定义MagicThread
的__bases__
来解决,但Python不允许这样做:这似乎是一个可以追溯到2003年的bug in Python。它还没有被修复,可能是因为在一个实例上动态地重新定义
__bases__
是一个奇怪的想法,而且可能是个坏主意!在现在,如果您不关心能否使用
isinstance(obj, ColliderGraph)
,那么上面的方法可能对您有用。或者它可能会以奇怪的、意想不到的方式失败。我真的不建议在任何生产代码中使用它,但我想我会分享它。在相关问题 更多 >
编程相关推荐