简体   繁体   中英

Extend an already existing object in Python

I'm trying to extend xml.ElementTree.Element . The problem is that the constructor gives me a ready made Element instance which I cannot extend without tampering with the source code of xml .

Is there a way to initialize a class that inherits from Element and copy the whole Element attributes into the SubClass?

import xml.ElementTree as ET

root = ET.parse('file.xml').getroot() # retrieves Element instance

class ExtendedElement(ET.Element):
    def __init__(self, element):
        pass
        # somehow initialize the ExtendedElement instance
        # with all methods and attributes of element
        # without copying each attribute individually
        # ie self.attrib = element.attrib

    def custom_method(self):
        print(self.attrib)

ext = ExtendedElement(root)

ext.custom_method()

assert root.attrib == ext.attrib
assert list(ext) == list(root)

Usually I would just go on and call self.__dict__.update(element.__dict__) , however Element doesn't seem to have a __dict__ (how is this even possible?).

I want to avoid copying all attributes individually as I might miss some hidden ones without knowing.

As @CristiFati suggested in the comments, you should use composition here.

class ExtendedElement:
    def __init__(self, element):
        self.element = element

    def custom_method(self):
        print(self.element.attrib)

ext = ExtendedElement(root)
ext.custom_method()

Then the 2 assertions will work with the correct alternation:

assert root.attrib == ext.element.attrib
assert list(ext.element) == list(root)

If you really need list(ext) to work then you can implement __iter__ :

def __iter__(self):
    return iter(self.element)

then the second assertion will work as is:

assert list(ext) == list(root)

Depending on your needs, you can hack ExtendedElement to expose all the attributes that element has by implementing __getattr__ :

def __getattr__(self, name):
    return getattr(self.element, name)

then

ext = ExtendedElement(root)
print(ext.attrib)

will output (with my test.xml):

{'b': '1'}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM