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.