Two __init__ functions

I saw the following codes:

class Basis:
    def __init__(self, M, N, T, U, lat):
        self.M = M
        self.N = N
        self.lat = lat
        self.U = U
        self.T = T

    def __init__(self, M, N, T, U, lat=None):
        self.M = M
        self.N = N
        self.lat = lat
        self.U = U
        self.T = T

Here we see two init functions. What are the differences? Is the first function redudant?

Yes, the first one gets overwritten by the second one and is never executed nor stored.

3 Likes

FWIW, the first one is still stored in the module’s bytecode and is briefly assigned to __init__ before being overwritten by the second.

>>> s = """
... class Basis:
...     def __init__(self, M, N, T, U, lat):
...         self.M = M
...         self.N = N
...         self.lat = lat
...         self.U = U
...         self.T = T
... 
...     def __init__(self, M, N, T, U, lat=None):
...         self.M = M
...         self.N = N
...         self.lat = lat
...         self.U = U
...         self.T = T
... """
>>> import dis
>>> dis.dis(s)
...
Disassembly of <code object Basis at 0x7f0bcfc164f0, file "<dis>", line 2>:
  2           0 RESUME                   0
              2 LOAD_NAME                0 (__name__)
              4 STORE_NAME               1 (__module__)
              6 LOAD_CONST               0 ('Basis')
              8 STORE_NAME               2 (__qualname__)

  3          10 LOAD_CONST               1 (<code object __init__ at 0x7f0bcfb4d9b0, file "<dis>", line 3>)
             12 MAKE_FUNCTION            0
             14 STORE_NAME               3 (__init__)

 10          16 LOAD_CONST               4 ((None,))
             18 LOAD_CONST               3 (<code object __init__ at 0x7f0bcfb4f330, file "<dis>", line 10>)
             20 MAKE_FUNCTION            1 (defaults)
             22 STORE_NAME               3 (__init__)
             24 RETURN_CONST             2 (None)
...
Disassembly of <code object __init__ at 0x7f0bcfb4d9b0, file "<dis>", line 3>:
...
Disassembly of <code object __init__ at 0x7f0bcfb4f330, file "<dis>", line 10>:
...
1 Like

In fact, that’s an important point to note. Revise the first __init__ method as follows, and execute the script without even instantiating a Basis object:

    def __init__(self, M, N, T, U, lat, V=print("Hi There!")):
        self.M = M
        self.N = N
        self.T = T
        self.U = U
        self.lat = lat
        self.V = V

Output:

Hi There!

While the Hi There! output is only a minor side effect, it does demonstrate that during its brief life, a mischievous method or function that immediately gets overwritten without ever having been called could have side effects. The above is, of course, not good coding style. :wink:

1 Like

I would consider that an implementation detail of the current version of CPython, though. There isn’t necessarily a reason to store the old function (even though it still needs to be defined to preserve the semantics of the original), aside from the compilation cost of verifying it can be safely discarded.