NoNoS
NoNoS

Reputation: 21

Change object attribute in class method without explicitly naming the attribute

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?

Upvotes: 1

Views: 215

Answers (1)

NoNoS
NoNoS

Reputation: 21

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

Upvotes: 1

Related Questions