如何从父类实例化子类
Posted
技术标签:
【中文标题】如何从父类实例化子类【英文标题】:How to instantiate a child class from parent class 【发布时间】:2018-07-05 00:36:51 【问题描述】:我想从父类创建一个子类。这是为了减少代码中的冗余。例如,
class Parent():
def __init__(self, a, b, c, d, e, f, g):
self.a = a
self.b = b
...
self.g = g
class Child1(Parent):
def __init__(self, a, b, c, d, e, f, g, h, i, j, k):
super().__init__(a, b, c d, e, f, g)
self.i = i
self.j = j
self.k = k
class Child2(Parent):
def __init__(self, a, b, c, d, e, f, g, h, x, y, z):
super().__init__(a, b, c d, e, f, g)
self.x = x
self.y = y
self.z = z
我不想一次又一次地为所有子类传递参数。有没有办法让 Child1 和 Child2 从 Parent 类?
我有 30 多个参数和许多子类。写出所有参数似乎非常多余。此外,它们都与父母共享相同的参数。
【问题讨论】:
Simple python inheritance的可能重复 定义子类时必须指定父类:Child1(Parent)
.
@DyZ 啊是的,这是一个错字
如果你有 30+ 个参数,那你的代码设计肯定有问题。你考虑过传字典吗?
嗯,我需要为深度学习调整一堆超参数...
【参考方案1】:
您在这里要执行的操作与实例化无关。这个词的意思是创建一个类的实例。您不能“从父类实例化子类”,因为类对象不是(除非在非常特殊的情况下)其基类的实例。
您要做的是消除一些样板。
Python 非常灵活——实例可以在任何地方定义属性,类可以为 __init__
和 __repr__
等方法指定任何签名。这非常强大,但这也意味着当你有一个非常重复的类层次结构,你必须重复自己很多。但是——因为 Python 非常灵活——你可以编写工具来为你生成所有重复的东西,或者你可以只使用语言附带的工具,比如@dataclass
:1
from dataclasses import dataclass
@dataclass
class Parent:
a: int
b: int
c: int
d: int
e: int
f: int
g: int
h: int
@dataclass
class Child1(Parent):
i: int
j: int
k: int
@dataclass
class Child2(Parent):
x: int
y: int
z: int
这就是定义类所需的全部内容,包括自动生成可以处理位置和关键字参数并将正确的东西转发给基类的__init__
方法,以及以某种有用的方式显示东西的__repr__
方法,以及静态类型提示 Mypy 可以为您检查,依此类推,无需任何重复:
>>> c1 = Child1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
>>> c1
Child1(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10, k=11)
>>> c1b = Child1(1, 2, 3, 4, 5, 6, 7, k=11, j=10, h=8, i=9)
>>> c1 == c1b
True
>>> c2 = Child2(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
>>> c1 == c2
False
如果您阅读文档,您会发现那里有更多的灵活性(attrs
中甚至更多),但默认值在 80% 的情况下都能满足您的需求。
@dataclass
在 Python 3.7 中添加。 a backport for 3.6 可以使用 pip install dataclasses
安装,但如果您需要使用 3.5 或 2.7,则需要像 attrs
这样的第三方库。另请查看 namedtuple
以了解非常简单的情况,它可以一直追溯到 2.6 和 3.1。
【讨论】:
【参考方案2】:从您的示例中不清楚继承在这里是否合适。孩子是否满足is a 关系,即孩子真的是父母的子类吗?如果没有,那么您应该考虑使用composition 而不是继承。
我建议组合,因为您在评论中提到,实例化父类并在“子”类中使用该instance。因此,您可以创建父类的实例并将其传递给“子”类的__init__()
,从而使用组合。
class Parent():
def __init__(self, a, b, c, d, e, f, g):
self.a = a
self.b = b
...
self.g = g
class Child1:
def __init__(self, parent, h, i, j, k):
self.parent = parent
self.h = h
self.i = i
self.j = j
self.k = k
例如,在子类中,您可以通过self.parent.a
访问父属性。
【讨论】:
【参考方案3】:您可以将所有参数作为列表传递给子类的__init__
,将尽可能多的参数传递给超类,并在子类本身中使用其余参数:
class Parent():
def __init__(self,a,b,c):
print(a,b,c)
class Child1(Parent):
def __init__(self, *args):
super().__init__(*args[:3]) # 3 for the parent
self.x, self.y = args[3:] # 2 for myself
print(self.x, self.y)
Child1(1,2,3,4,5)
#1 2 3
#4 5
#<__main__.Child1 object at 0x7f5d70c3c9e8>
【讨论】:
出于项目特定的原因,我不喜欢使用 *args。似乎没有办法在 python 中从父级实例化一个子级 @MoneyBall 就是您要问的“我如何在不使用*args
的情况下做与*args
相同的事情?如果是这样,那是不可能的,但类似的事情是。例如,如果您想要一个具有固定年龄数的函数,但该固定数字在函数创建时由变量指定,您可以编写一个函数来创建该函数。以上是关于如何从父类实例化子类的主要内容,如果未能解决你的问题,请参考以下文章