在运行时扩展实例

时间:2015-08-09 17:48:31

标签: python inheritance instance

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

注意:代码 工作,我在运行时询问有关扩展类实例的想法,更好的选项和意见(性能,可靠性)。

例如,让我们说我原来的课程是Foo,我想"延伸它"与酒吧。

我现在的具体限制是:

  • 兼容Python 2,即使我对Python 3的具体内容感到好奇(如果有的话)
  • 我从不同的库中获取一个对象我想添加功能(注意:这是一个"旧样式类")
  • 我需要它来保持它的父母所以isinstance(例如,Foo)继续工作
  • 不得从第一个类重新运行 init (有状态连接)
  • 能够在" new"上测试它的继承权将会很高兴。 class(即:isinstance(instance,Bar))

我想知道是否与元类或混合内容有关。但是我还没有做到这一点。

我尝试了什么

用作基础:

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

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

foo = Foo()

创建一个引用前一个

的新对象

它可以工作,但它创建了一个新对象,我想不这样做(我认为测试是无用的开销):

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

请赐教。

2 个答案:

答案 0 :(得分:3)

CAVEAT:这不是简洁的编程!但你知道: - )

最简单的方法是让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

回应另一条评论:是的,这真的很容易:)

答案 1 :(得分:2)

如果您希望isinstance工作,可以将栏添加到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