如何在 python 中克服 "classmethod is not callable"

How to overcome "classmethod is not callable" in python

看完Various errors in code that tries to call classmethods, , 和其他人很明显 Python class 方法不可调用。 “为什么”似乎没有得到很好的回答,只是说不需要它显然是不正确的,正如关于这个主题的许多问题所表明的那样。

无论如何,我有一个 XML,在同一位置使用了许多不同的标签,每个标签都需要基本相似但又不同的处理方式。我的想法是为个别案例设置一个 base class 和 subclasses,每个案例都能够解析自己的部分(元素)并使用它们进行操作。像这样(简体):

import xml.etree.ElementTree as ET


class base():        
    parsers = dict()
    @classmethod
    def parseXml(cls, x:str):
        parser = base.parsers.get(x)
        parser(cls, x)  # different class, but same base (and all called cls elements are only in base class)
                # or parser(el)


class derivedOne(base):
    def __init__(self):
        self.one = None
    @classmethod
    def parseXml(cls, x:str):

        d1 = derivedOne()
        d1.one = 'one+'+x
    
    base.parsers['xmlTagOne']=parseXml 


class derivedTwo(base):
    def __init__(self):
        self.two = None
    @classmethod
    def parseXml(cls, x:str):
        d2 = derivedTwo()
        d2.two = 'two+'+x

    base.parsers['xmlTagTwo']=parseXml

    if __name__ == "__main__":
        base.parseXml('xmlTagOne')
        base.parseXml('xmlTagTwo')

已找到解析器,但无法调用。

当然,所有的构造函数都可以从一个地方用一些 if/else 逻辑调用,但这不是很优雅,最重要的是它不允许(正如我计划的那样)添加额外的 handler/parser class不改变基数 class...

有什么方法可以保留这个“在单个 class 中添加新标签的解析”吗?

您可以使用 __init_subclass__base.parsers 中存储对新子 class 的引用。

class Base:        
    parsers = dict()
    @classmethod
    def parseXml(cls, x:str):
        parser = base.parsers.get(x)
        parser(cls, x)

    def __init_subclass__(cls, /, tag, **kwargs):
        super().__init_subclass__(**kwargs)  # removed ...(cls, ...
        Base.parsers[tag] = cls


class DerivedOne(Base, tag="xmlTagOne"):
    def __init__(self):
        self.one = None

    @classmethod
    def parseXml(cls, x:str):
        ...


class DerivedTwo(Base, tag="xmlTagTwo"):
    def __init__(self):
        self.two = None
    @classmethod
    def parseXml(cls, x:str):
        ...


if __name__ == "__main__":
    base.parsers['xmlTagOne'].parseXml(some_string)
    base.parsers['xmlTagTwo'].parseXml(some_other_string)

Base.__init_subclass__ 在子 class 创建后立即被调用,基 class 列表中的任何关键字参数传递给 __init_subclass__。每个 subclass 保存到 Base.parsers 带有指定的标签。


注意:我在这里完全忽略了您是否应该使用 classes 和 class 方法的问题。