Is a constructor __init__ necessary for a class in Python?

20,098

Solution 1

I see a misconception here between a constructor--constructing the object and initializing the object:

Python's use of __new__ and __init__?

Use __new__ when you need to control the creation of a new instance. Use __init__ when you need to control initialization of a new instance.

So we must be careful here.

I read that the constructor is like the first argument passed to the class, which makes sense to me since the parameters seem to be passed to the class via the __init__ method.

The constructor is not passed to the class, to be precise the result of the constructor (__new__) will be the first argument for every instance method in the class or its sub-classes (note: __new__ works only for new-style classes):

class A:
    def __new__(self):
            return 'xyz'

See what happens when you call the class (create the object):

>>> A()
'xyz'
>>> type(A())
<class 'str'>

Calling the class no longer return instance of type A, because we changed the mechanism of the constructor __new__. Actually by doing so you alter the whole meaning of your class, not only, this is pretty much hard to decipher. It's unlikely that you'll switch the type of object during the creating time of that specific object. I hope this sentence makes sense, if not, how will it make sense in your code!

class A:
    def __new__(self):
            return 'xyz'

    def type_check(self):
            print(type(self))

Look what happens when we try to call type_check method:

>>> a = A()
>>> a
'xyz'
>>> a.type_check()
AttributeError: 'str' object has no attribute 'type_check'

a is not an object of class A, so basically you don't have access to class A anymore.

__init__ is used to initialize the object's state. Instead of calling methods that will initialize the object's members after it's created, __init__ solves this issue by initializing the object's members during creation time, so if you have a member called name inside a class and you want to initialize name when you create the class instead of calling an extra method init_name('name'), you would certainly use __init__ for this purpose.

So when I 'call' the class, I pass it the parameters from the __init__ method?

When you call the class, you pass the parameters (to) __init__ method?

Whatever arguments you pass the class, all the parameters will be passed to __init__ with one additional parameter added automatically for you which is the implied object usually called self (the instance itself) that will be passed always as the left-most argument by Python automatically:

class A:
    def __init__(self, a, b):
        self.a = a
        self.b = b 

        A(  34,  35) 
 self.a = 34 |    |  
             |    | 
             |    | self.b = 35  
  init(self, a,   b)
        |
        |
        | 
       The instance that you created by calling the class A() 

Note: __init__ works for both classic classes and new style classes. Whereas, __new__ works only for new-style classes.

Solution 2

No, the constructor is just the method that is called to construct the object. It is not passed anywhere. Rather the object itself is passed automatically to all methods of the class.

Constructor is not required if you don't have anything to construct but usually you have something to do in the beginning.

Solution 3

It is not too difficult to understand Python class constructors but sure a little tricky especially if we already hear some object oriented programming terms from other languages that support OOP like C++ or Java.

Main purpose of a class constructor is to create objects with instances customized to a specific initial state. This is very important to understand in Python because data attributes (member variables) need not be declared and they spring into existence when they are first assigned to. So, good place to group all data attributes of an instance is constructor.

Any data attribute assigned outside of all functions of a class are shared by all instances of the class. Here, Python gets trickier, since it has mutable data types and immutable data types.

For example, see following code snippet:


    class MyClass:
        i = 3
        arr = []

    x = MyClass()
    x.i = 4
    x.arr.append('x')

    y = MyClass()
    y.i = 5
    y.arr.append('y')

    MyClass.arr.append('m')

    print "{}, {}, {}".format(x.i, y.i, MyClass.i)
    print "{}, {}, {}".format(x.arr, y.arr, MyClass.arr)

and the output will be:


    4, 5, 3
    ['x', 'y', 'm'], ['x', 'y', 'm'], ['x', 'y', 'm']

Since integer is immutable data type in Python, each assignment creates new copy of integer object, this could be misleading to some programmers since it appears that each instance has its own private copy of member variable. List data type is mutable, so above code snippet modifies same copy of list from all instances.

So one need not write constructor for Python class if all members are shared by all instances of the class, otherwise it is a good practice to write a constructor and group all private data members inside it.

In above code snippet, if programmer really wanted a private data member, i for class instances, then instead of relying on immutable property one should write a constructor and initialize variable.

Modified code to use constructor:


    class MyClass:
        arr = []
        def __init__(self, i):
            self.i = i


    x = MyClass(4)
    y = MyClass(5)
    print "{}, {}".format(x.i, y.i)

output will be:


    4, 5

Hope that helps a little on top of useful knowledge that was already shared by others on this thread. Good luck.

Solution 4

Python classes work a little different to classes in other languages. For example, there are no private attributes in python. Just naming conventions to imply that a method or member variable is not intended for public use (a leading _).

While every class has to have the attributes __new__ and __init__, which together build what other languages might call a constructor, the base python classes implements thos methods. You do not have to override them, if you do not need to.

This is perfectly fine:

class A:
   def hello(self):
        print('Hello, World')

a = A()
a.hello()

In python __new__(cls, ...) is first used to create a class instance of the requested cls. Then the newly created instance is passed to __init__(self, ...) as self.

The __new__ and __init__ methods both receive the arguments you pass to the construction expression. This is how python calls m = MyClas(1, 2, 3).

class A:
    def __new__(cls, *args, **kwargs):
        print('In __new__')
        print(args)
        print(kwargs)
        return object.__new__(cls) # create a new object of type cls

    def __init__(self, *args, **kwargs):
        print('In __init__')
        print(args)
        print(kwargs)


a = A(1, 2, c=3)

Results in:

In __new__
(1, 2)
{'c': 3}
In __init__
(1, 2)
{'c': 3}
Share:
20,098
sampy
Author by

sampy

Updated on July 09, 2022

Comments

  • sampy
    sampy almost 2 years

    I read that the constructor is like the first argument passed to the class, which makes sense to me since the parameters seem to be passed to the class via the __init__ method. For example,

    class NewsStory(object):
        def __init__(self, guid, title, subject, summary, link):
            self.guid = guid
            self.title = title
            self.subject = subject
            self.summary = summary
            self.link = link
    
        def get_guid(self):
            return self.guid
    
        def get_title(self):
            return self.title
    
        def get_subject(self):
            return self.subject
    
        def get_summary(self):
            return self.summary
    
        def get_link(self):
            return self.link
    firstStory = NewsStory('Globally Unique Identifier', \
        'first_title','first_subject','This is an example \
        sumary','[email protected]')
    
    print firstStory.get_guid() # prints Globally Unique Identifier
    

    So when I 'call' the class, I pass it the parameters from the __init__ method? I'm new to classes, everything I read I find hard to understand and confusing. Thanks!

    Edit 1

    I found this question helpful in explaining some things, like the difference between new and init, sorry, I don't know how to add a link, gotta cut and paste: What can `__init__` do that `__new__` cannot?

  • MaxNoe
    MaxNoe almost 8 years
    __init__ is not a constructor in the traditional sense. The object already exists. __new__ would be the constructor, which you rarely have to touch in python.
  • Will
    Will almost 8 years
    @MaxNoe, you're technically correct, but coming form other languages, a constructor is the best comparison, as that's where you pass initialization parameters to the object. I changed the wording in my edit to clarify this. In PHP, for example, __construct() can still reference $self, but there is nothing comparable to __new__().
  • Will
    Will almost 8 years
    OP used Python 2 syntax in his question! See his use of the print statement. That's ridiculous.
  • Will
    Will almost 8 years
    OP is using Python 2, not Python 3.
  • sampy
    sampy almost 8 years
    when I call a = A() I get <__main__.A instance at 0x1019df368> When I call the method type check [a = A(), a.type_check(), in my text editor] I get <type 'instance'>. Perhaps we have different versions of Python?
  • direprobs
    direprobs almost 8 years
    I edited my answer and added a small note. Yes, If you're using Python 2.X there are two types of classes, classic classes and new-style classes. Note that __new__ works only for new-style classes, classes that inherit from the predefined class object. So you need to add class object as a super-class for class A, class A(object) only in 2.X. So again __new__ only for new style classes. What is the difference between old style and new style classes in Python?
  • direprobs
    direprobs almost 8 years
    Though __new__ is pretty much advanced feature and you won't come across it that often in code. I just wanted to show the difference between __init__ and __new__. __init__ is not the constructor, it's the method used to initialize the object's members (e.g., name, address, phone...) during the creation time of that object (when you call the class). So you shouldn't think of the example I provided for __new__ method as a valid or widely used code. It's quite the opposite, I just wanted to show the difference between the two (__init__ and __new__).