After reading Various errors in code that tries to call classmethods, Why are python static/class method not callable?, Are staticmethod and classmethod in python not callable? and others it is clear that Python class methods are not callable. The "why" does not seem to be answered that well and just saying that it is not needed is plainly not true as manifested by numerous questions on this topic.
Anyway, I have a XML with many different tags used in the same position each requiring fundamentally similar, but different nonetheless, handling. My idea was to have a base class and subclasses for the individual cases, each able to parse its own part (element) and operate with these. Like this (simplified):
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')
The parser is found, but not callable.
Of course all the constructors could be called from one place with some if/else logic, but that is not very elegant and most importantly it does not allow (as I planned) to add additional handler/parser classes without changing the base class...
Is there any way to keep this "add parsing of new tag in single class"?
You can use __init_subclass__
to store a reference to a new subclass in base.parsers
.
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__
is called after immediately after the subclass is created, with any keyword arguments in the base class list passed through to __init_subclass__
. Each subclass is saved to Base.parsers
with the specified tag.
Note: I'm ignoring the issue of whether you should use classes and class methods at all here.