I want to expand the class Foo
by the class Bar
, the issue that I have is that I can't expand it in the usual way (class Foo(Bar)
) because the class Bar
is somewhat dynamically generated.
我想通过类Bar扩展类Foo,我遇到的问题是我无法以通常的方式扩展它(类Foo(Bar)),因为类Bar在某种程度上是动态生成的。
I made this small example to illustrate my desired outcome:
我做了一个小例子来说明我想要的结果:
class Bar:
def super_cool_function():
print("Cool")
class Foo:
def __init__(self, another_class):
# I want to extend Foo by another_class
# Desired result
foobar = Foo(Bar)
foobar.super_cool_function()
Again this is not what I'm looking for:
这不是我想要的:
class Foo(Bar):
pass
foobar = Foo()
foobar.super_cool_function()
2 个解决方案
#1
21
"The class Bar
is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo
), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.
“类Bar有点动态生成”这很好......只要它遵循蓝图(应该由Foo扩展的类),你可以在这里利用python闭包。通过在内部创建并从函数返回它来动态创建新类。
def get_class(superclass):
class Foo(superclass):
def __init__(self, ...):
...
return Foo
DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.
这是你在python中看到的常见模式 - 利用闭包来动态创建回调和类。
The answer above assumes that Bar
is correctly defined, when it in fact is not. The super_cool_function
is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.
上面的答案假设Bar是正确定义的,而实际上并非如此。 super_cool_function缺少self参数。始终使用第一个参数(实例本身)作为第一个属性传入实例方法。
So, the correct definition for Bar
would be:
因此,Bar的正确定义是:
class Bar:
def super_cool_function(self):
print("Cool")
Now, defining get_class
with the simplest definition of the inner class Foo
:
现在,使用内部类Foo的最简单定义来定义get_class:
def get_class(superclass):
class Foo(superclass):
pass
return Foo
DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
myobj.super_cool_function()
# Cool
#2
4
Your desired use is a little strange:
你想要的用途有点奇怪:
foobar = Foo(Bar)
You're constructing a Foo
instance by handing it the Bar
class object, and expecting to get back something that acts like a Bar
instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.
您正在构建一个Foo实例,方法是将它交给Bar类对象,并期望得到一些像Bar实例那样的东西。通常,代理类被设计为将对象代理到某个地方,或者在某个地方查找,而不仅仅是构造一个没有参数的对象。
But, other than that oddness, which just means an __init__
method that constructs the object, this is just a bog-standard proxy class. So:
但是,除了奇怪之外,这只是构造对象的__init__方法,这只是一个沼泽标准的代理类。所以:
class Foo:
def __init__(self, cls):
self._inst = cls()
def __getattr__(self, name):
return getattr(self._inst, name)
def __setattr__(self, name, value):
if name in {'_inst'}:
super().__setattr__(name, value)
else:
setattr(self._inst, name, value)
def __delattr__(self, name):
delattr(self._inst, name)
Of course you still won't be able to call that super_cool_function
on a foobar
any more than you could on a Bar
instance, because it's defined as a method and doesn't have a self
parameter. But you'll get the same error from the Foo
instance that you would have gotten from a Bar
instance:
当然,你仍然无法在一个foobar上调用super_cool_function比在Bar实例上更多,因为它被定义为一个方法,并且没有自我参数。但是你会从你从Bar实例得到的Foo实例中得到同样的错误:
>>> foobar.super_cool_function
<bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
>>> foobar.super_cool_function()
TypeError: super_cool_function() takes 0 positional arguments but 1 was
#1
21
"The class Bar
is somewhat dynamically generated" That's fine... as long as it follows the blueprint (of a class that should be extended by Foo
), you can leverage python closures here. Dynamically create a new class by creating it inside, and returning it from a function.
“类Bar有点动态生成”这很好......只要它遵循蓝图(应该由Foo扩展的类),你可以在这里利用python闭包。通过在内部创建并从函数返回它来动态创建新类。
def get_class(superclass):
class Foo(superclass):
def __init__(self, ...):
...
return Foo
DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
This is a common pattern you'll see in python - leveraging closures to dynamically create callbacks and classes.
这是你在python中看到的常见模式 - 利用闭包来动态创建回调和类。
The answer above assumes that Bar
is correctly defined, when it in fact is not. The super_cool_function
is missing a self parameter. Instance methods are always called with the first parameter (the instance itself) automatically being passed in as the first attribute.
上面的答案假设Bar是正确定义的,而实际上并非如此。 super_cool_function缺少self参数。始终使用第一个参数(实例本身)作为第一个属性传入实例方法。
So, the correct definition for Bar
would be:
因此,Bar的正确定义是:
class Bar:
def super_cool_function(self):
print("Cool")
Now, defining get_class
with the simplest definition of the inner class Foo
:
现在,使用内部类Foo的最简单定义来定义get_class:
def get_class(superclass):
class Foo(superclass):
pass
return Foo
DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
myobj.super_cool_function()
# Cool
#2
4
Your desired use is a little strange:
你想要的用途有点奇怪:
foobar = Foo(Bar)
You're constructing a Foo
instance by handing it the Bar
class object, and expecting to get back something that acts like a Bar
instance. Normally, a proxy class is designed to take an object to proxy to, or look on up somewhere, not just construct one with no arguments.
您正在构建一个Foo实例,方法是将它交给Bar类对象,并期望得到一些像Bar实例那样的东西。通常,代理类被设计为将对象代理到某个地方,或者在某个地方查找,而不仅仅是构造一个没有参数的对象。
But, other than that oddness, which just means an __init__
method that constructs the object, this is just a bog-standard proxy class. So:
但是,除了奇怪之外,这只是构造对象的__init__方法,这只是一个沼泽标准的代理类。所以:
class Foo:
def __init__(self, cls):
self._inst = cls()
def __getattr__(self, name):
return getattr(self._inst, name)
def __setattr__(self, name, value):
if name in {'_inst'}:
super().__setattr__(name, value)
else:
setattr(self._inst, name, value)
def __delattr__(self, name):
delattr(self._inst, name)
Of course you still won't be able to call that super_cool_function
on a foobar
any more than you could on a Bar
instance, because it's defined as a method and doesn't have a self
parameter. But you'll get the same error from the Foo
instance that you would have gotten from a Bar
instance:
当然,你仍然无法在一个foobar上调用super_cool_function比在Bar实例上更多,因为它被定义为一个方法,并且没有自我参数。但是你会从你从Bar实例得到的Foo实例中得到同样的错误:
>>> foobar.super_cool_function
<bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
>>> foobar.super_cool_function()
TypeError: super_cool_function() takes 0 positional arguments but 1 was