Jonathan Bechtel
Jonathan Bechtel

Reputation: 3607

Setting an attribute value for an inherited class when it's not an argument in __init__

I'm creating a class that's going to be a collection of other classes assembled together when it's initiated.

Right now, the init function for my class looks like this:

class RandomForest():
    def __init__(self, n_estimators=10, min_leaf=5, sample_size = 2/3, min_impurity=1e-5):
    self.n_estimators = n_estimators
    self.tree         = None
    self.min_leaf     = min_leaf
    self.sample_size  = sample_size
    self.min_impurity = min_impurity
    self.trees        = [self.tree(min_leaf=self.min_leaf, impurity_threshold=self.min_impurity) for i in range(n_estimators)]

The idea is that there are going to be two subclasses of the class RandomForest that are going to use different classes for the attribute self.tree, and that's what I'd like to modify at initiation for each one.

Right now I have this for a subclass of Random Forest:

class RandomForestRegressor(RandomForest):
    def __init__(self):
        self.tree = DecisionTreeRegressor
        super().__init__() 

In my head I'm setting the value of self.tree to the class I want to initiate, and then self.trees will be a list with 10 separate instances of DecisionTreeRegressor(), but instead I'm getting the error message:

TypeError: 'NoneType' object is not callable

So apparently the value of self.tree is not being updated.

Also, I do do not want this to be a choice that the user makes when the class is initiated and it should be set automatically without their choice.

What is the correct way to set this attribute for an inherited class of Random Forest?

**EDIT: ** This will be done in Python 3.

Upvotes: 0

Views: 720

Answers (2)

Paweł BB Drozd
Paweł BB Drozd

Reputation: 4913

If you set attribute tree before call superclass init, you'll have it in your class instance, but calling after that superclass init you do also:

    self.tree         = None

which replace your previously set tree with value None.

You can:

  • call super().__init__() before you set tree variable if nothing is dependent on self.tree value
class SupClass:
    def __init__():
        self.tree = None

class SubClass(SupClass):
    def __init__():
        super().__init__() # It would set self.tree = None
        self.tree = Something # It will set self.tree to Something

  • wrap conditionally setting tree in your superclass like: self.tree = self.tree if hasattr(self, 'tree') else None which will set None only if there is no self.tree set before.
class SupClass:
    def __init__():
        self.tree = self.tree if hasattr(self, 'tree') else None  # Note, it check if value is defined before, in other case you may need to check if value is not None too.

class SubClass(SupClass):
    def __init__():
        self.tree = Something # It will set self.tree to Something
        super().__init__() # It will leave Something, because there is value

  • put it as SupClass init argument
class SupClass:
    def __init__(tree=None):
        self.tree = tree

class SubClass(SupClass):
    def __init__():
        super().__init__(tree=Something) # Note that your SupClass init method has no argument tree, you use it only in superclass init call.

Upvotes: 1

Daniel Roseman
Daniel Roseman

Reputation: 599480

You set the value, but then call the super method which immediately sets it to None, hence the error.

The solution is simply to set it after calling super.

Upvotes: 2

Related Questions