0

I have a problem where I want to change the class of some child elements in a class recursively.

I have a working solution, which is the following:

class PerformanceAggregator:
    def __init__(self, collection: pf.GenericPortfolioCollection):
        self.collection = collection
        self.change_children()

    def __getattr__(self, item):
        return getattr(self.collection, item, None)

    def change_children(self):
        for i in range(len(self.children)):
            if isinstance(self.children[i], pf.GenericPortfolioCollection):
                self.children[i] = PerformanceAggregator(self.children[i])

However, the change_children method is not very pythonic. It would be better with

class PerformanceAggregator2:
    def __init__(self, collection: pf.GenericPortfolioCollection):
        self.collection = collection
        self.change_children()

    def __getattr__(self, item):
        return getattr(self.collection, item, None)

    def change_children(self):
        for child in self.children:
            if isinstance(child, pf.GenericPortfolioCollection):
                child = PerformanceAggregator(child)

But this method does not work as intended. It does not replace the "child" element as the first method does. Do anybody have an idea about what is wrong?

  • In your second example, `child` is a variable that assigned to one of `self.children`. When you reassign it using `child = PerformanceAggregator(child)`, you are not changing the reference in `self.children` at all. You are just assigning the variable `child` to the new instance, but nothing else happens with it since you never update the parent object. – James Dec 12 '19 at 11:03
  • 1
    Does this answer your question? [Assigning values to variables in a list using a loop](https://stackoverflow.com/questions/4687364/assigning-values-to-variables-in-a-list-using-a-loop) – Raj Dec 12 '19 at 11:04
  • Answer is in the duplicate. Mandatory reading for you: [this article](https://nedbatchelder.com/text/names.html) explains in great length and depth all you need to know about python "variables". – bruno desthuilliers Dec 12 '19 at 11:08
  • And for the pythonic way to deal with this case: [use `enumerate()`](https://docs.python.org/3/library/functions.html#enumerate) so you get both the child and it's index. – bruno desthuilliers Dec 12 '19 at 11:09

1 Answers1

1

When you're looping through self.children, you're assigning child to PerformanceAggregator(child) but not necessarily updating the child element in self.children.

This should work:

     def change_children(self):
         for (val,child) in enumerate(self.children):
             if isinstance(child, pf.GenericPortfolioCollection):
                 self.children[val] = PerformanceAggregator(child)
Plutian
  • 2,276
  • 3
  • 14
  • 23
RemPot
  • 26
  • 2