【问题标题】:discriminating whether python object is subclass of current __init__ method判断 python 对象是否是当前 __init__ 方法的子类
【发布时间】:2025-11-29 21:05:01
【问题描述】:

这是一个奇怪的问题。我遇到过几次情况,我想在 python 对象的__init__ 末尾执行一些操作。我只想在真正的类(叶类)的__init__ 中做最后一件事。如果在 self __init__ 方法的超类中,我绝对不想这样做。有没有好的方法来做到这一点?我承认这可能是一件愚蠢的事情。但这让我很好奇它是否以及如何完成。

【问题讨论】:

  • 我不明白你的问题。你试过什么?
  • 你只是说你希望每个叶类能够做超类的事情,然后再做自己的事情(而不是为超类的实例做自己的事情)?或者您是否尝试以编程方式检测一个类是否为叶类,以便您可以使用一个方法在两种情况下执行不同的操作?还是……?
  • 目前的情况是 ORM 想要自动存储 PersistentObject 子类的新实例之一。我知道 [许多] 其他方法可以使这个特定用例工作,但我很好奇可能的解决方案可以在 init 本身中进行区分。

标签: python init


【解决方案1】:

如果你想让一些代码在叶类中运行,在__init__ 的末尾,而不是在基类中运行……只需覆盖叶类中的__init__。例如:

class Base(object):
    def __init__(self):
        print('Base initializing')
class Intermediate(Base):
    pass
class Leaf(Intermediate):
    def __init__(self):
        super(Leaf, self).__init__()
        print('Leaf initializing')

>>> o = Base()
Base initializing
>>> o = Intermediate()
Base initializing
>>> o = Leaf()
Base initializing
Leaf initializing

如果您尝试从Base.__init__ 之类的方法中以编程方式检测selfBase 还是Base 的某个子类……好吧,通常这是个坏主意,而您实际上想使用方法覆盖,如上所述。但这很容易做到。例如:

class Base(object):
    def __init__(self):
        if type(self) != Base:
            print('Some subclass of Base initializing')
class Leaf(Base):
    pass

>>> obj = Leaf()
Some subclass of Base initializing

(如果您担心有人可能会破坏您的层次结构,使得某些既不是Base 也不是它的子类的对象最终可能会调用Base.__init__,你确定那将是一件邪恶的事情,而不是聪明的猴子修补事情,您可以随时查看issubclass。)


如果您尝试以编程方式检测,在Base.__init__ 之类的方法中,base 是否是“真正的类”……那么,您需要定义它的含义。这是否意味着“不是 PEP3119 意义上的抽象基类”? “还没有定义子类”? “有一些关键方法的实现”?你想做的任何事情都可能是可行的,但有些会比其他人更难。 (例如,要检测是否有人对您的类进行了子类化,您可能需要构建一个自定义元类。)

【讨论】:

  • 显然,“邪恶”和“聪明的猴子补丁”之间的区别很好......
  • @DanielRoseman:试图阻止在 Python 中恶意滥用您的代码确实没有意义,但是很多新手仍然在寻求方法来做到这一点,所以......我会让他们定义他们的邪恶自己的方式。当然他们自己的方式是错误的,因为你可以通过猴子是住在一个秘密的火山巢穴中,还是住在一个带着黄色帽子的主人的公寓里来判断,但是随着他们对 Python 越来越熟悉,他们会知道这一点。跨度>
  • 我希望没有什么比把 if self.__class__ == MyClass:.. 或其他地方的东西更丑的了。
  • @SamanthaAtkins:正如我在回答中所说,“通常这是一个坏主意,你实际上想使用方法覆盖”。在 Python 中,通常是一个坏主意的事情往往是丑陋的,有时是故意的。如果你真的想要,你可以将丑陋隐藏在元类或方法或类装饰器中——它的优点是把它分解出来,所以你也只需要做一次——但如果这是你想要的,你必须在某处做(或者做一些更丑陋的事情,比如sys.getframe,或者更难以理解,比如默认的标志参数)。
  • 谢谢。我还没有想出如何为此做最小的元类解决方案,但我倾向于这个方向。对于有问题的用例,我不能只使用方法覆盖,因为目标是将一个从不持久的对象保存到数据存储中,并且只有在它完成初始化之后。所以在 init 链结束之前调用 overrode 方法仍然会错过在第一次保存时创建的 init 数据。我可以通过存储对象以供以后持久保存来推迟保存。但那是让语言决定我什么时候做的工作,看起来不优雅。
最近更新 更多