<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def add_attribute(self, attrkey, attrvalue, append=False, oldvalue=None):
 """ Add an attribute to this feature. Feature attributes are stored as nested dictionaries. Each feature can only have one ID, so ID attribute mapping is 'string' to 'string'. All other attributes can have multiple values, so mapping is 'string' to 'dict of strings'. By default, adding an attribute that already exists will cause the old value to be overwritten. If the `append` option is true, the new attribute value will not overwrite the old value, but will be appended as a second value. (Note: ID attributes can have only 1 value.) If the `oldvalue` option is set, the new value will replace the old value. This is necessary for updating an attribute that has multiple values without completely overwriting all old values. (Note: The `append` option is ignored when `oldvalue` is set.) """

        # Handle ID/Parent relationships
        if attrkey == 'ID':
            if self.children is not None:
                oldid = self.get_attribute('ID')
                for child in self.children:
                    child.add_attribute('Parent', attrvalue,
                                        oldvalue=oldid)
            self._attrs[attrkey] = attrvalue
            if self.is_multi:
                self.multi_rep._attrs[attrkey] = attrvalue
                for sibling in self.multi_rep.siblings:
                    sibling._attrs[attrkey] = attrvalue
            return

        # Handle all other attribute types
        if oldvalue is not None:
            if attrkey in self._attrs:
                assert oldvalue in self._attrs[attrkey]
                del self._attrs[attrkey][oldvalue]
        if attrkey not in self._attrs or append is False:
            self._attrs[attrkey] = dict()
        self._attrs[attrkey][attrvalue] = True