【问题标题】:Is it possible to dynamically inherit from a class that is only known at runtime in python?是否可以从仅在 python 运行时才知道的类动态继承?
【发布时间】:2019-01-19 15:00:55
【问题描述】:

我想通过 Bar 类扩展 Foo 类,我遇到的问题是我无法以通常的方式 (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()

【问题讨论】:

  • 什么时候知道Barclass Foo(X): 工作得很好,即使 X 是一个变量,而不是父类的字面名称。
  • 我应该指出,为了让 Foo 的实例可以调用 super_cool_function,它需要 self 参数 (def super_cool_function(self):)。我不会编辑您的问题来更正它,因为这会使 abarnert 的答案无效。

标签: python class inheritance closures


【解决方案1】:

TL;DR:是的,使用 python 闭包

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 缺少 self 参数。实例方法总是在第一个参数(实例本身)作为第一个属性自动传入时调用。

所以,Bar 的正确定义是:

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

现在,用内部类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】:

    你想要的用途有点奇怪:

    foobar = Foo(Bar)
    

    您正在通过将Bar 类对象传递给Foo 实例来构造它,并期望得到类似于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)
    

    当然,你仍然不能在 foobar 上调用 super_cool_function,就像在 Bar 实例上一样,因为它被定义为方法并且没有 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 
    

    【讨论】:

    • 你为什么使用object.__setattr__而不是super().__setattr__
    • @Aran-Fey 可能只是 Guido 最初的 Python 2.2 示例或其他东西遗留下来的习惯,我看不出有什么理由不使用super,所以……编辑了。
    猜你喜欢
    • 1970-01-01
    • 2023-03-08
    • 2018-03-10
    • 2019-07-10
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多