Skip to content

Specialized sub-classes of Generic never call __init__ #192

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

Closed
gvanrossum opened this issue Mar 23, 2016 · 2 comments
Closed

Specialized sub-classes of Generic never call __init__ #192

gvanrossum opened this issue Mar 23, 2016 · 2 comments
Milestone

Comments

@gvanrossum
Copy link
Member

See http://bugs.python.org/issue26391 .

"""
A specialized sub-class of a generic type never calls __init__ when it is instantiated. See below for an example:

from typing import Generic, TypeVar

T = TypeVar('T')
class Foo(Generic[T]):
    def __init__(self, value: T):
        self.value = value

Bar = Foo[str]

foo = Foo('foo')
bar = Bar('bar')

print(type(foo), end=' ')
print(foo.value)

print(type(bar), end=' ')
print(bar.value) # AttributeError

I would expect Foo[str], Foo[int], etc to be equivalent to Foo at run-time. If this is not the case it might deserve an explicit mention in the docs. At the moment, behaviour is confusing because an instance of Foo is returned that does not have any of its attributes set.
"""

@gvanrossum gvanrossum added this to the 3.5.2 milestone Mar 23, 2016
@gvanrossum
Copy link
Member Author

(Update, copied from the CPython bug:)

Actually, I just realized why this is. Generic.__new__() calls next_in_mro.__new__(_gorg(cls)). Here next_in_mro is just object, but _gorg(cls) is Foo, in the case where cls is Bar (i.e. Foo[str]). The _gorg() call strips the [str] part of the type.

So far so good. Where it gets interesting is that, in general in Python, whenever __new__(cls, ...) returns an object whose class is not cls, it is presumed to be an already properly initialized object!

I think I can fix this by calling __init__() explicitly in the case where _gorg(cls) is not cls.

The reason, BTW, why it strips the [str] part of the class is because that's what PEP 484 says, in the same section where it says that NodeT and Nodeint are allowed:

At runtime the type is not preserved, and the class of x is just
Node in all cases.

So this bit of code is trying to do the right thing but obviously hasn't been tested much, because mypy disallows that syntax.

@gvanrossum
Copy link
Member Author

See also 37a3dd5 which backports the fix to Python 2.

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

1 participant