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.
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.
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).
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.
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.
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.
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).
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.