1

I have a class Node that I built using python parent child relationship class. This class defines the parent/children relationship needed to build a tree. In my application, I am building a balance sheet.

class Node:
_parent = None

def __init__(self, name='', attributes=None, children=None, parent=None):
    self.name = name
    self.children = children if children is not None else []
    self.parent = parent
    if children is not None:
        for child in children:
            child.parent = self

@property
def parent(self):
    return self._parent() if self._parent is not None else None

@parent.setter
def parent(self, newparent):
    oldparent = self.parent
    if newparent is oldparent:
        return
    if oldparent is not None:
        oldparent.children.remove(self)
    if self not in newparent.children:
        newparent.children.append(self)
    self._parent = weakref.ref(newparent) if newparent is not None else None

I also define a subclass LineItem that I use to populate the nodes of my tree. When a LineItem object with a given attribute (e.g. balance) gets added to the tree, I would like that attribute to be added and rolled up the tree. For example, if node 1 has two children node 2 and 3 with each a balance of 10 and 20 respectively, then Node 1 would get a balance of 30.

class LineItem(Node):
def __init__(self, enabled=True, balance=None, native_curr=None, reported_curr='USD', *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.enabled = enabled
    self.balance = balance
    self.currency = native_curr
    self.report_curr = reported_curr
    # propagate the balance up the balance sheet
    super().addrollup(self.balance)

I created a method in the class Node that works well if the attribute is always balance.

# propagate the quantity up
def addrollup(self, quantity):
    curr_parent = self.parent
    if quantity is not None:
        while curr_parent is not None:
            if curr_parent.balance is not None:
                curr_parent.balance += quantity
            else:
                curr_parent.balance = quantity
            curr_parent = curr_parent.parent

How would I write this function if I didn't want to explicitly call out "balance"? Is it possible to write a function generic enough that it takes an argument to define what attribute should be rolled up?

1
  • Have you tried overloading setattr operator? That could allow generic approach to setting the attribute values. Commented Jul 26, 2021 at 18:43

1 Answer 1

1

Thank you for your comment Željko Jelić. After looking at setattr and getattr, I realized that they could be used to pass the name as an argument instead of using the self.attribute = syntax.

I rewrote the function as

    def addrollup(self, attr_name, value):
    curr_parent = self.parent
    if value is not None:
        while curr_parent is not None:
            if getattr(curr_parent, attr_name) is not None:
                setattr(curr_parent, attr_name, getattr(curr_parent, attr_name)+value)
            else:
                setattr(curr_parent, attr_name, value)
            curr_parent = curr_parent.parent
Sign up to request clarification or add additional context in comments.

1 Comment

Note that when using setattr you need to be careful not to end up with infinite recursive call. For instance, use dict in order to access attribute and reassign def __setattr__(self, attr, value): self.__dict__[attr] = value should be a safe way to set a generic attribute value. You will, of course, need to adapt this form to your particular problem.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.