在运行时扩展一个实例

extend an instance at runtime

这个问题在 StackExchange 上被拒绝了,我还没有在 Whosebug 上找到答案。

注意: 代码 确实 有效,我正在询问想法、更好的选择和意见(性能、可靠性)在运行时扩展 class 个实例。

例如,假设我原来的 class 是 Foo,我想 "extend it" 和 Bar。

我现在的具体限制是:

不知是否与newmetaclass、mix-ins有关。但是我还没有取得任何成就。

我试过的

用作基础:

class Foo:
    def foo(self): return 'foo'

class Bar:
    def bar(self): return self.foo() + 'bar'

foo = Foo()

创建一个新的 object 参考以前的

它有效,但它创建了一个新的 object,我想不这样做(我认为测试是无用的开销):

class Bar(Foo, object):
    def __init__(self, foo):
        self.__foo = foo
    def __getattr__(self, name):
        try:
            return getattr(self.__foo, name)
        except:
            raise AttributeError
    def bar(self):
        return self.foo() + 'bar'

bar.foo() # OK
bar.bar() # OK
isinstance(bar, Foo) # OK
isinstance(bar, Bar) # OK

正在更新实例字典

几乎成功了,但是 Bar 没有出现在继承中:

foo.__class__.__dict__.update(Bar.__dict__)
foo.bar()            # does work
isinstance(foo, Foo) # True
isinstance(foo, Bar) # False :(

使用types.MethodType

差不多,但是 Bar 没有出现在继承中,我必须测试我正在修补的属性是否是可调用的:

for k, v in Bar.__dict__.iteritems():
    if callable(v):
        setattr(foo, k, types.MethodType(v, foo))

foo.foo() # OK
foo.bar() # OK
isinstance(foo, Foo) # OK
isinstance(foo, Bar) # False

请赐教

警告:这不是干净的编程!但是你知道:-)

最简单的做法是让 Bar 成为 Foo 的子类,然后动态更改实例的类型:

class Foo:
    def foo(self): return 'foo'

class Bar(Foo):
    def bar(self): return self.foo() + 'bar'

foo = Foo()

foo.__class__ = Bar

print foo.bar()

回复评论中的问题:

>>> class Foo:
...     def foo(self): return 'foo'
... 
>>> class Bar(Foo):
...     def bar(self): return self.foo() + 'bar'
... 
>>> foo = Foo()
>>> 
>>> foo.__class__ = Bar
>>> 
>>> print foo.bar()
foobar
>>> isinstance(foo, Bar)
True
>>> isinstance(foo, Foo)
True

回复另一条评论:是的,真的就是这么简单:)

如果你想让 isinstance 工作,你可以将 Bar 添加到 Foo.__bases__:

class Foo:
    def foo(self): return 'foo'

class Bar:
    def bar(self): return self.foo() + 'bar'

foo = Foo()
Foo.__bases__ = Foo.__bases__ + (Bar,)

print(foo.bar())
print isinstance(foo, Foo) 
print(isinstance(foo, Bar))
foobar
True
True