Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weird behavior when calling super().__init__ #53

Closed
devashishshankar opened this issue Nov 29, 2019 · 5 comments
Closed

Weird behavior when calling super().__init__ #53

devashishshankar opened this issue Nov 29, 2019 · 5 comments

Comments

@devashishshankar
Copy link

devashishshankar commented Nov 29, 2019

Let's say I want to call superclass init in my child class:

from pyfields import field, init_fields, get_field


class A:
    a = field(str, check_type=True)

    @init_fields()
    def __init__(self):
        pass


class B(A):
    b = field(str, check_type=True)

    @init_fields()
    def __init__(self):
        super(B, self).__init__(a=self.a)
        pass

print(B('a', 'b'))

This fails with the following Error:

    super(B, self).__init__(a=self.a)
TypeError: __init__() missing 1 required positional argument: 'b'

If I try the following:

from pyfields import field, init_fields, get_field


class A:
    a = field(str, check_type=True)

    @init_fields(a)
    def __init__(self):
        pass


class B(A):
    b = field(str, check_type=True)

    @init_fields()
    def __init__(self):
        super(B, self).__init__(a=self.a)
        pass

print("Init before calling B", B.__init__)
B(a='22', b='33')
print("Init after calling B", B.__init__)

This leads to the following:

Init before calling B <function B.__init__ at 0x108951cb0>
Init after calling B <function A.__init__ at 0x108951f80>

This is very dangerous, and was leading to a weird error in my code. Took me a while to figure out this was the cause.

I think the superclass constructor is being overriden by the child class. setattr(objtype, '__init__', new_init) in init_makers.py

Is calling superclass constructor not supported?

I am using version 1.0.2

@smarie
Copy link
Owner

smarie commented Nov 30, 2019

wow, very strange indeed ! This should definitely not happen. It is probably related to the fact that the __init__ descriptor is not called in an intuitive way by super . I'll have a look, thanks a lot for reporting !

@smarie
Copy link
Owner

smarie commented Nov 30, 2019

For some reason that seems to be a python bug, super(B, self).__init__(a) is not equivalent to A.__init__(self, a) when the __init__ method is a method descriptor: InitDescriptor.__get__(obj, objtype) is called but when it is called through super, objtype is not replaced with A.

I'll have to find a workaround, that should not be too difficult. In the meantime, you can use A.__init__(self, a=self.a) as a constructor, it works.

@smarie
Copy link
Owner

smarie commented Nov 30, 2019

I found a workaround but for python 3.6+ (where __setname__ callback is called when the init descriptor is attached to the class). Unfortunately for earlier versions I still have no way to determine which class owns the init method to be created. I really thought that objtype in InitDescriptor.__get__(obj, objtype) was reliable...

@devashishshankar
Copy link
Author

Thanks, using A.__init__(self, a=self.a) works for me.

@smarie smarie closed this as completed in a67d4f7 Dec 10, 2019
smarie added a commit that referenced this issue Dec 10, 2019
@smarie
Copy link
Owner

smarie commented Dec 10, 2019

I finally found a "clever" way to solve this :)

It will ship in 1.0.3 in a few minutes when travis has completed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants