【问题标题】:Selecting a subclass at instantiation in Python在 Python 中实例化时选择子类
【发布时间】:2020-03-31 23:03:42
【问题描述】:

我想在实例化时选择一个子类以从某些类中选择特定属性。我已经解决了以下问题:

代码

class Foo:
    a = "foo"

    def __init__(self, dtype=Bar):
            self.__class__ = dtype


class Bar:
    b = "bar"


class Baz(Bar):
    c = "baz"

演示

Foo(dtype=Bar).b
# 'bar'

Foo(dtype=Baz).b
# 'bar'

Foo(dtype=Baz).c
# 'baz'

这给出了所需的结果,从Bar 中选择特定属性,同时可以选择使用Baz 扩展功能。然而,与子类化不同的是,我们无法访问Foo 的属性。

Foo(dtype=Baz).a
# AttributeError: 'Baz' object has no attribute 'a'

在某些情况下,并非所有属性都需要,因此子类化 Foo(Baz) 不是首选。

在 Python 中实现此目的的惯用模拟是什么?

【问题讨论】:

  • 为什么不能只使用继承?您可以动态选择子类,例如var = Bar; var()
  • 这听起来像XY problem。我不知道这样做会不会是惯用的。
  • @KentShikama 选择var = Bar() 仍然排除Foo 中的属性。
  • docs.python.org/3/reference/datamodel.html#object.__new__,如果__new__返回一个实例(包括子类),__init__将被调用。但这都是type.__call__执行的;另见stackoverflow.com/questions/6966772/…
  • 也就是说,__new__ 返回不同的类型应该很少见;我只在 FFI 相关代码中将NULL 映射到None

标签: python subclass


【解决方案1】:

如果您真的想要BarBaz 的实例,为什么首先要创建Foo 的实例?相反,将Foo 设为BarBaz 的工厂。

class Bar:
    b = "bar"

class Baz(Bar):
    c = "baz"

class Foo:
    a = "foo"

    def __new__(cls, dtype=Bar):
        return dtype()

【讨论】:

    【解决方案2】:

    正如我在 cmets 中提到的,只需使用普通继承即可。

    class Foo:
        a = "foo"
    
    class Bar(Foo):
        b = "bar"
    
    class Baz(Foo):
        c = "baz"
    
    # Example use
    import random
    class_to_instantiate = Bar if random.choice([True, False]) else Baz
    print(class_to_instantiate().a)
    

    输出

    foo
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多