Returning class to itself in python

Viewed 95

Very simple question here, but I am new to python as an object oriented programming language. I am trying to write a class. Imagine it is organized as follows:

class myClass:
    def __init__(self,a,b,runit=True):
        self.a = a
        self.b = b
        if runit:
            self.run_func()

    def run_func(self):
        self.c = self.a*self.b
        return

So as you can see the class is initialized with just a and b. It defaults to initialize c from those arguments, but it need not. Now let me illustrate three use cases that I think should behave the same, but are not:

# Use 1
test = myClass(5,2)
print(test.c)

# Use 2
test = myClass(5,2,runit=False)
test.run_func()
print(test.c)

# Use 3
test = myClass(5,2,runit=False).run_func()
print(test.c)

This returns the following:

10
10
Traceback (most recent call last):

  File "<ipython-input-37-cb854baa3a0c>", line 23, in <module>
    print(test.c)

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

Why can the instantiated class not be operated on immediately and pipe this result to test in one step? In my head, (1) and (2) are the same set of operations except one is broken into two steps and the other is done in one line.

And, more importantly, how can I fix this by editing my class to behave in the expected manner?

5 Answers

run_func should return self:

    def run_func(self):
        self.c = self.a*self.b
        return self

stating return without a value following it, is the same as writing return None. You get this exception because None has no attribute named c.

In the 3rd case, test is assigned the return value of run_func(). It has a bare return which returns None, so test = None.

at # Use 3 myClass(5,2,runit=False).run_func() returns None

to fix you could return self:

def run_func(self):
        self.c = self.a*self.b
        return self

test = myClass(5,2,runit=False).run_func()
print(test.c)

output:

10

or you should not set your flag runit to False and use:

class myClass:
    def __init__(self,a,b,runit=True):
        self.a = a
        self.b = b
        if runit:
            self.run_func()

    def run_func(self):
        self.c = self.a*self.b

test = myClass(5,2)
print(test.c)

output:

10

Lets look at the method call in question:

test = myClass(5,2,runit=False).run_func()

Let's break that down. First, you construct an instance of myClass and then you call run_func on that instance. It's the return value of run_func that you assign to test and since run_func doesn't return anything test is None resulting in your error.

As another way to see this, try the following:

class myClass:
    def __init__(self,a,b,runit=True):
        self.a = a
        self.b = b
        if runit:
            self.run_func()

    def run_func(self):
        self.c = self.a*self.b
        return 11

test = myClass(5,2,runit=False).run_func()
print(test) # will print 11

In case 3

 test = myClass(5,2,runit=False).run_func()
 print(test.c)

test is not the object, but the return of the run_func(), which is null and indeed has no c attribute

Related