Why can I set properties during instantiation through __init__, but not through another method?

Question:

This is working

class a:
    def __init__(self,ka,sif):
        self.ka = ka
        self.sif = sif
    def b(self):
        pass

c = a("d","e")
c
print(c.ka,c.sif)

but

This is not working

class a:
    def __init__(self):
        pass
    def b(self,ka,sif):
        self.ka = ka
        self.sif = sif

c = a().b("d","e")
c
print(c.ka,c.sif)

Why?

I expected the get same result. Why these are not have same results.

Asked By: swarthy03

||

Answers:

a("d","e") will call __init__ and return the new instance of the class a. Regular methods do not have this behavior.

The b method does not return anything (so it implicitly returns None); if you want to be able to chain that method, add return self at the end.

Answered By: Unmitigated

To be even more explicit about how to fix this:

c = a()
c.b("d", "e")
print(c.ka, c.sif)

Now we’re not depending on b to return anything (which it doesn’t).

Answered By: Charles Duffy

a is an instance of type. Like any other class, an instance of type is callable because type.__call__ is defined, so a() is equivalent to type.__call__(a).

You can imagine the definition of __call__ looks something like this, if it were written in pure Python:

class type:

    def __call__(self, *args, **kwargs):
        obj = self.__new__(self, *args, **kwargs)
        if isinstance(obj, self):
            obj.__init__(*args, **kwargs)
        return obj

If you were to unwrap this, a call like

c = a()

is like the following code:

c = a.__new__()
if isinstance(c, a):
    c.__init__()

So, you should be able to see that

c = a()
c.b(...)

is quite different from

c = a().b(...)

in terms of what is actually assigned to the name c. In the latter case, you lose the reference to the new instance of a once its b method completes.

Answered By: chepner
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.