在 Python 中实例化时选择子类
Posted
技术标签:
【中文标题】在 Python 中实例化时选择子类【英文标题】:Selecting a subclass at instantiation in 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__
执行的;另见***.com/questions/6966772/…
也就是说,__new__
返回不同的类型应该很少见;我只在 FFI 相关代码中将NULL
映射到None
。
【参考方案1】:
如果您真的想要Bar
或Baz
的实例,为什么首先要创建Foo
的实例?相反,将Foo
设为Bar
和Baz
的工厂。
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
【讨论】:
以上是关于在 Python 中实例化时选择子类的主要内容,如果未能解决你的问题,请参考以下文章