Search code examples
pythonclassoopobjectnonetype

Why does Init function return Object type but other functions return the NoneType


I wrote a python program to try to grade my ml predictions using object oriented programming and I am trying to chain functions together. Like say:

answers = predictionsGrader().merge_on('PassengerId').compare("Survived_x", "Survived_y").grade()

However, my code started to throw errors of attribute error.

AttributeError: 'NoneType' object has no attribute 'compare'

After trying to understand what the problem was, I realized that although the initialization was returning an object,

<class 'predictionsGrader.predictionsGrader'>

the function which was called after the initialization (which is the merge_on function) was returning a NoneType

<class 'NoneType'>

Please what could be wrong. Here's the full code:

import pandas as pd

class predictionsGrader():

    def __init__(self, predictions, target):
        self.correct = []
        self.predictions = predictions
        self.target = target
        return


    def merge_on(self, row):
        self.row = row
        self.md = pd.merge(self.predictions, self.target, on=[self.row])
        return


    def compare(self, predicted_target, confirmed_target):
        self.predicted_target = predicted_target or "predicted_target"
        self.confirmed_target = confirmed_target or "confirmed_target"
        return


    def grade(self):
        for x in range(len(self.md[self.predicted_target])):
            if (self.md[self.predicted_target][x] == self.md[self.confirmed_target][x]):
                self.correct.append("right")
            else:
                self.correct.append("wrong")
        return self.correct

Solution

  • If you want a fluid interface like that, your methods (other than __init__) need to return self.

    class predictionsGrader():
    
        def __init__(self, predictions, target):
            self.correct = []
            self.predictions = predictions
            self.target = target
    
        def merge_on(self, row):
            self.row = row
            self.md = pd.merge(self.predictions, self.target, on=[self.row])
            return self
    
        def compare(self, predicted_target, confirmed_target):
            self.predicted_target = predicted_target or "predicted_target"
            self.confirmed_target = confirmed_target or "confirmed_target"
            return self
    
        def grade(self):
            for x in range(len(self.md[self.predicted_target])):
                if (self.md[self.predicted_target][x] == self.md[self.confirmed_target][x]):
                    self.correct.append("right")
                else:
                    self.correct.append("wrong")
            return self.correct
    

    __init__ shouldn't return anything - it's an initializer, not a constructor.