Python3 通用继承层次结构
Python3 generic inheritance hierarchy
这个问题是针对 python 3. 假设我有一个像这样的 class 层次结构
class Base():
def calculate():
return 0
class Derived1(Base):
def calculate():
# some calculation
class Derived2(Base):
def calculate():
# some calculation
现在,我想要做的是创建一个 class,它定义了一种从 Derived classes 继承的通用方法,然后覆盖计算。换句话说,本着 C++ 模板的精神,避免复制 subclasses 代码,而是指定 subclassing 的通用方式,然后能够定义 subclasses作为一个衬里,如下图:
# pseudocode
class GenericDerived5(someGenericBase):
def calculate():
return super().calculate() + 5
class GenericDerived6(someGenericBase):
def calculate():
return super().calculate() + 5
class Derived5_1 = GenericDerived5(Derived1)
class Derived6_1 = GenericDerived6(Derived2)
(计算不是字面意思,只是说明继承结构的组合性)
这段代码会是什么样子,我需要哪些来自 python3 的相关工具?听说过 metaclasses,但不是很熟悉。
class 工厂函数体内的定义
去那里最直接的方式是真的直接 - 但可能会感觉有点尴尬:
def derived_5_factory(Base):
class GenericDerived5(Base):
def calculate(self):
return super().calculate() + 5
return GenericDerived5
def derived_6_factory(Base):
class GenericDerived6(Base):
def calculate(self):
return super().calculate() + 6
return GenericDerived6
Derived5_1 = derived_5_factory(Derived1)
Derived6_2 = derived_6_factory(Derived2)
不方便的部分是您的 classes 需要通用基础
必须在函数体内定义。这样,Python 重新执行
class
语句本身,具有不同的 Base,利用
在 Python class 中是第一个 class 个对象。
此代码的不便之处在于 (1) class 主体必须在函数内部,并且 (2) 它可能是完全错误的方法:
多重继承
如果您可以拥有额外的继承级别 - 这是您的示例的唯一区别,那么这是“正确”的方法。实际上,除了在它们的继承链中明确包含前一个“GenericDerived”classes 之外,它们的行为完全符合预期:
class Base():
def calculate():
return 0
class Derived1(Base):
def calculate(self):
return 1
class Derived2(Base):
def calculate(self):
return 2
# mix-in bases:
class MixinDerived5(Base):
def calculate(self):
return super().calculate() + 5
class MixinDerived6(Base):
def calculate(self):
return super().calculate() + 6
Derived5_1 = type("Derived5_1", (MixinDerived5, Derived1), {})
Derived6_2 = type("Derived6_2", (MixinDerived6, Derived2), {})
在这里,不是使用 class
语句,而是使用 type
调用创建动态 class,同时使用需要动态基础的 class 和该动态基础作为其 bases
参数。就是这样 - Derived5_1
是一个完全可用的 Python class,其继承链中包含两个 Base
请注意,Python 的 super()
将完全按照常识期望它做的事情,在到达之前通过额外的中介“派生”classes“重新路由”自己“根据”。所以,这就是我在粘贴上面的代码后在交互式控制台上得到的:
In [6]: Derived5_1().calculate()
Out[6]: 6
In [7]: Derived6_2().calculate()
Out[7]: 8
混合 class,粗略地说,是一个 class,它不打算直接实例化或充当独立的基础 class(除了其他,更专业的混入 classes),但提供另一个 class 可以继承的一小部分功能。
在这种情况下,您的 GenericDerived
classes 是混合的完美示例:您不是在创建 GenericDerived
的实例,但您可以继承它们以添加calculate
方法到您自己的 class.
class Calculator:
def calculate(self):
return 9
class Calculator1(Calculator):
def calculate(self):
return super().calculate() + 5
class Calculator2(Calculator):
def calculate(self):
return super().calculate() + 10
class Base(Calculator):
...
请注意,Base
和 Calculator
层次结构彼此独立。 Base
除了提供其他功能外,还提供基本的 calculate
功能。 Base
的子 class 可以使用从 Base
继承的 calculate
(通过 Calculator
),或者它可以从子 class 继承也是 Calculator
。
class Derived1(Base):
...
class Derived2(Base, Calculator1):
...
class Derived3(Base, Calculator2):
...
这个问题是针对 python 3. 假设我有一个像这样的 class 层次结构
class Base():
def calculate():
return 0
class Derived1(Base):
def calculate():
# some calculation
class Derived2(Base):
def calculate():
# some calculation
现在,我想要做的是创建一个 class,它定义了一种从 Derived classes 继承的通用方法,然后覆盖计算。换句话说,本着 C++ 模板的精神,避免复制 subclasses 代码,而是指定 subclassing 的通用方式,然后能够定义 subclasses作为一个衬里,如下图:
# pseudocode
class GenericDerived5(someGenericBase):
def calculate():
return super().calculate() + 5
class GenericDerived6(someGenericBase):
def calculate():
return super().calculate() + 5
class Derived5_1 = GenericDerived5(Derived1)
class Derived6_1 = GenericDerived6(Derived2)
(计算不是字面意思,只是说明继承结构的组合性) 这段代码会是什么样子,我需要哪些来自 python3 的相关工具?听说过 metaclasses,但不是很熟悉。
class 工厂函数体内的定义
去那里最直接的方式是真的直接 - 但可能会感觉有点尴尬:
def derived_5_factory(Base):
class GenericDerived5(Base):
def calculate(self):
return super().calculate() + 5
return GenericDerived5
def derived_6_factory(Base):
class GenericDerived6(Base):
def calculate(self):
return super().calculate() + 6
return GenericDerived6
Derived5_1 = derived_5_factory(Derived1)
Derived6_2 = derived_6_factory(Derived2)
不方便的部分是您的 classes 需要通用基础
必须在函数体内定义。这样,Python 重新执行
class
语句本身,具有不同的 Base,利用
在 Python class 中是第一个 class 个对象。
此代码的不便之处在于 (1) class 主体必须在函数内部,并且 (2) 它可能是完全错误的方法:
多重继承
如果您可以拥有额外的继承级别 - 这是您的示例的唯一区别,那么这是“正确”的方法。实际上,除了在它们的继承链中明确包含前一个“GenericDerived”classes 之外,它们的行为完全符合预期:
class Base():
def calculate():
return 0
class Derived1(Base):
def calculate(self):
return 1
class Derived2(Base):
def calculate(self):
return 2
# mix-in bases:
class MixinDerived5(Base):
def calculate(self):
return super().calculate() + 5
class MixinDerived6(Base):
def calculate(self):
return super().calculate() + 6
Derived5_1 = type("Derived5_1", (MixinDerived5, Derived1), {})
Derived6_2 = type("Derived6_2", (MixinDerived6, Derived2), {})
在这里,不是使用 class
语句,而是使用 type
调用创建动态 class,同时使用需要动态基础的 class 和该动态基础作为其 bases
参数。就是这样 - Derived5_1
是一个完全可用的 Python class,其继承链中包含两个 Base
请注意,Python 的 super()
将完全按照常识期望它做的事情,在到达之前通过额外的中介“派生”classes“重新路由”自己“根据”。所以,这就是我在粘贴上面的代码后在交互式控制台上得到的:
In [6]: Derived5_1().calculate()
Out[6]: 6
In [7]: Derived6_2().calculate()
Out[7]: 8
混合 class,粗略地说,是一个 class,它不打算直接实例化或充当独立的基础 class(除了其他,更专业的混入 classes),但提供另一个 class 可以继承的一小部分功能。
在这种情况下,您的 GenericDerived
classes 是混合的完美示例:您不是在创建 GenericDerived
的实例,但您可以继承它们以添加calculate
方法到您自己的 class.
class Calculator:
def calculate(self):
return 9
class Calculator1(Calculator):
def calculate(self):
return super().calculate() + 5
class Calculator2(Calculator):
def calculate(self):
return super().calculate() + 10
class Base(Calculator):
...
请注意,Base
和 Calculator
层次结构彼此独立。 Base
除了提供其他功能外,还提供基本的 calculate
功能。 Base
的子 class 可以使用从 Base
继承的 calculate
(通过 Calculator
),或者它可以从子 class 继承也是 Calculator
。
class Derived1(Base):
...
class Derived2(Base, Calculator1):
...
class Derived3(Base, Calculator2):
...