【问题标题】:Python: add a parent class to a class after initial evaluationPython:在初始评估后向类添加父类
【发布时间】:2026-02-23 21:30:01
【问题描述】:

一般 Python 问题

我正在导入一个具有以下类结构的 Python 库(称为 animals.py):

class Animal(object): pass

class Rat(Animal): pass

class Bat(Animal): pass

class Cat(Animal): pass

...

我想为每个物种类(RatBatCat,...)添加一个父类(Pet);但是,我无法更改要导入的库的实际来源,因此它必须是运行时更改。

以下似乎有效:

import animals

class Pet(object): pass

for klass in (animals.Rat, animals.Bat, animals.Cat, ...): 
    klass.__bases__ = (Pet,) + klass.__bases__

这是在 Python 中将父类注入继承树而不修改要修改的类的源定义的最佳方法吗?

激励环境

我正在尝试将持久性移植到控制实验室设备的大型库中。与它混为一谈是不可能的。我想试试 ZODB 的Persistent。我不想编写 mixin/facade 包装库,因为我正在处理 100 多个类和需要更新的应用程序代码中的大量导入。我正在通过仅在我的入口点上进行黑客攻击来测试选项:设置数据库,如上所示进行修补(但在动物模块上通过自省而不是显式列出来拉取物种类),然后在我退出时关闭数据库。

Mea Culpa / 请求

这是一个故意笼统的问题。我对注入父母和 cmets 的不同方法感兴趣,这些方法的优缺点。我同意这种运行时的诡计会让代码变得非常混乱。如果我选择 ZODB,我会做一些明确的事情。目前,作为 python 的普通用户,我对一般情况感到好奇。

【问题讨论】:

  • 不要这样做。如果你真的不能修改导入的模块,如果你真的可以写一个新的父类,你至少必须能够看到它,所以你不能在你的模块中简单地重新实现它们吗?如果没有,尽可能创建使用Pet 作为mixin 的子类——class PetRat(Pet, Rat): pass。几乎可以肯定你不应该在运行时这样做,还有 另一种方法。
  • @agf 该库由第三方支持。复制/粘贴重新实现不是一个好的长期解决方案。我认为通过混合 Pet 来创建 PetXats 的包装库会更好;然而,正如我在编辑中所说,这主要是一个学术/python 内部问题。
  • 我认为你已经概述了“方法”,而不是实际阅读库模块,用正则表达式重写它,然后编译它。
  • @agf:class Blah(Mixin, Main): pass 比动态插入新的父级更好吗?

标签: python oop inheritance monkeypatching


【解决方案1】:

您的方法几乎就是如何动态地做到这一点。真正的问题是:这个新的父类增加了什么?如果您尝试将自己的方法插入到已经存在的类中的方法链中,并且它们没有正确编写,那么您将无法;如果您要添加原始方法(例如接口层),那么您可以只使用函数。

我是一个拥抱 Python 动态特性的人,使用您提供的代码不会有任何问题。确保您有良好的单元测试(动态或非动态;),并且修改继承树实际上可以让您做您需要的事情,并享受 Python!

【讨论】:

  • 这被证明是那些运作良好的临时解决方案之一。老实说,我还没有检查 ZODB 内部以弄清楚 Persistent 做了什么,所以我不确定我要添加什么,但这似乎有效。我倾向于同意动态完成工作是可以的,动态本身就是一个维护问题。这感觉就像是就行了。
【解决方案2】:

你应该努力不这样做。这很奇怪,很可能会以眼泪收场。

正如@agf 提到的,您可以将 Pet 用作 mixin。如果您告诉我们更多关于为什么要插入父类的信息,我们可以帮助您找到更好的解决方案。

【讨论】:

  • 我同意这很奇怪,不太可能成为一个好的长期解决方案。我更新了其他信息。