Home > Enterprise >  Understanding / Using __init__ method of dict
Understanding / Using __init__ method of dict

Time:04-03

I came across this idea how to make a Python class serializeable.

class FileItem(dict):
    def __init__(self, name):
        dict.__init__(self, name=name)

x = FileItem("test")
print(x)

{'name': 'test'}

This works fine, but I do not understand how. I thought dict.__init__ calls the __init__ method from the dict class to create a new instance and so I expected this to work:

x = dict.__init__(name="test")

This results in the following error:

TypeError: descriptor '__init__' of 'dict' object needs an argument

Why is this different to the example above?

CodePudding user response:

So, notice that you've not provided a second argument to __init__,

>>> x = dict.__init__(name="test")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__init__' of 'dict' object needs an argument

It require the instance, i.e self, as the first argument. Of course, if you create an appropriate instance and pass that, __init__ returns None:

>>> x = dict.__init__({}, name="test")
>>> print(x)
None

Because __init__ is not a constructor, it is an initializer. In Python these are two distinct steps in the object initialization process.

The "constructor" is __new__:

>>> dict.__new__(dict)
{}

Read about it in the Python data model docs.

Also, for the sake of decency, you probably shouldn't be sprinkling:

x = dict.__new__(dict)

In real code. But this is how the mechanics of it work. All of this happens in type.__call__, by the way. type is the parent class that creates classes, a metaclass. (It is also itself a type... type(type) is type just like type(dict) is type... )

>>> type.__call__(dict)
{}

CodePudding user response:

__new__ creates new instances but __init__ is used for initializing a newly created instance, so __init__ requires an instance to work with.

When you do dict.__init__(name='test') then this isn't operating on any instance, hence the error. With dict.__init__(self, name=name) on the other hand, you do pass the instance self as an argument and hence it works.

Typically you'd use super().__init__(name=name) which takes care of providing self as an argument and also works when you decide to changes base classes later on.

CodePudding user response:

The difference is the self property which isn't passed, the __init__ property applies its computations on the instance (self) passed in, if the __init__ function doesn't have any context, it throws an error
Have a great day, Lukas.

  • Related