通过Python中的参数扩展类

时间:2018-08-12 21:09:04

标签: python class inheritance closures

我想用类Foo来扩展类Bar,我遇到的问题是我不能以通常的方式(class Foo(Bar))来扩展它,因为Bar是动态生成的。

我做了一个小例子来说明我想要的结果:

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()

同样,这是我正在寻找的 不是

class Foo(Bar):
    pass

foobar = Foo()
foobar.super_cool_function()

2 个答案:

答案 0 :(得分:22)

“类Bar是动态生成的”那很好...只要遵循蓝图(应该由Foo扩展的类),就可以在这里利用python闭包。通过在内部创建新类并从函数返回它来动态创建新类。

def get_class(superclass):
    class Foo(superclass):
        def __init__(self, ...):
           ...

    return Foo

DynamicFoo = get_class(Bar)
myobj = DynamicFoo()

这是您会在python中看到的常见模式-利用闭包动态创建回调和类。


以上答案假定Bar正确定义,而实际上却没有正确定义。 super_cool_function缺少自我参数。始终使用第一个参数(实例本身)自动调用实例方法作为第一个属性。

因此,Bar的正确定义是:

class Bar:
   def super_cool_function(self):
       print("Cool")

现在,使用内部类get_class的最简单定义来定义Foo

def get_class(superclass):
    class Foo(superclass):
        pass

    return Foo

DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
myobj.super_cool_function()
# Cool

答案 1 :(得分:4)

您想要的用途有点奇怪:

foobar = Foo(Bar)

您正在通过将Foo类对象传递给它来构造一个Bar实例,并期望取回类似Bar实例的行为。通常,代理类的目的是使一个对象可以代理或在某个地方查找,而不仅仅是构造没有参数的对象。

但是,除了那种奇怪的意思,这只是意味着构造对象的__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)

当然,您仍然无法像在super_cool_function实例上那样在foobar上调用Bar,因为它被定义为方法并且不会被调用。 t有一个self参数。但是您将从Foo实例中得到的错误与从Bar实例中得到的错误相同:

>>> 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