在运行时扩展一个实例
extend an instance at runtime
这个问题在 StackExchange 上被拒绝了,我还没有在 Whosebug 上找到答案。
注意: 代码 确实 有效,我正在询问想法、更好的选择和意见(性能、可靠性)在运行时扩展 class 个实例。
例如,假设我原来的 class 是 Foo,我想 "extend it" 和 Bar。
我现在的具体限制是:
- Python 2 兼容,即使我很好奇 Python 3 如果有任何细节
- 我从另一个库中得到一个 object 我想添加功能(注意:这是一个 "old style class")
- 我需要它来保持 parents 所以 isinstance(instance, Foo) 继续工作
- 它不能re-run第一个class的init(有状态连接)
- 如果能够在 "new" class 上测试它的继承就好了(即:isinstance(instance, Bar))
不知是否与new、metaclass、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
这个问题在 StackExchange 上被拒绝了,我还没有在 Whosebug 上找到答案。
注意: 代码 确实 有效,我正在询问想法、更好的选择和意见(性能、可靠性)在运行时扩展 class 个实例。
例如,假设我原来的 class 是 Foo,我想 "extend it" 和 Bar。
我现在的具体限制是:
- Python 2 兼容,即使我很好奇 Python 3 如果有任何细节
- 我从另一个库中得到一个 object 我想添加功能(注意:这是一个 "old style class")
- 我需要它来保持 parents 所以 isinstance(instance, Foo) 继续工作
- 它不能re-run第一个class的init(有状态连接)
- 如果能够在 "new" class 上测试它的继承就好了(即:isinstance(instance, Bar))
不知是否与new、metaclass、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