What is the difference between classes initialized with (and without) __init

2

I'm a beginner in Python and wanted to understand a difference. The two classes below produce exactly the same result and the variables are publicly the same in both classes:

class c():
    t = "abc"
    print (t)
    for a in range (3):
        print (a)

class d():
    def __init__(self):
        self.t = "abc"
        print (self.t)
        self.a = 0
        for self.a in range(0, 3):
            print(self.a)

c1 = c()
d1 = d()

Result:

abc
0
1
2
abc
0
1
2

Why then should I use the constructor __init__ if at the end of the day the results are the same?

    
asked by anonymous 18.09.2018 / 00:06

1 answer

8

They are not the same. In his example it was almost purely coincidental. Just do not instantiate the class c that will see what happens.

This is due to the fact that classes are only a limiting scope in Python. You can enter codes normally inside the class, not just definitions of fields and methods, as they do in other languages. The difference is that this code will execute when the class is defined.

class c():
    t = "abc"
    print (t)
    for a in range (3):
        print (a)

This will already display on the terminal even if the class is not instantiated, other than the class d , which implements the initializer method, which will have the logic executed only when instantiated.

You can use this to define compatibility with different versions of Python. Let's say a method has features that vary depending on the version being run and you want to keep both, you could do something like:

import sys

class Foo:

  if sys.version_info[0] == 3:
    def something(self):
     return 'Python 3'
  else:
    def something(self):
      return 'Python 2'

foo = Foo()

print(foo.something())

See working at Python 3 and Python 2

Obviously I would not do something like this for such a simple method, but when you start working with some more drastic differences between versions, such as using the __str__ or __unicode__ , this approach begins to make sense.

Not to mention the difference that when you define a field without associating with self , you are defining a class attribute, whereas when used against self it will be an instance attribute. This will make all difference when the type worked is changeable, since being changeable and being class attribute, once modified the modification will be reflected in all instances.

class Foo:
    field = []

a = Foo()
a.field.append(1)

print(a.field)  # [1]

b = Foo()

print(b.field)  # [1]

See working at Repl.it

However, if used within __init__ , with self , the output of b.field would be [] , since it would be an independent list of a.field , even if they are instances of the same class. In your case, c.t will be a class attribute while d.t will be an instance attribute.

    
18.09.2018 / 00:15