classification
Title: typing: Specialized sub-classes of Generic never call __init__
Type: behavior Stage:
Components: Versions: Python 3.5
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: Kai Wohlfahrt, gvanrossum, python-dev
Priority: normal Keywords:

Created on 2016-02-19 11:52 by Kai Wohlfahrt, last changed 2016-04-05 15:37 by gvanrossum. This issue is now closed.

Messages (5)
msg260519 - (view) Author: Kai Wohlfahrt (Kai Wohlfahrt) Date: 2016-02-19 11:52
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.
msg262306 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-03-23 20:41
You've hit a type where PEP 484 and mypy disagree.

The PEP shows a few examples of this:
https://www.python.org/dev/peps/pep-0484/#instantiating-generic-classes-and-type-erasure

However when I feed the examples from the PEP to mypy I get an error on each of the last two lines:

-----
from typing import TypeVar, Generic
T = TypeVar('T')
class Node(Generic[T]):
    pass
x = Node[T]()
y = Node[int]()
-----
b.py:5: error: Invalid type "b.T"
b.py:5: error: Generic type not valid as an expression any more (use '# type:' comment instead)
b.py:6: error: Generic type not valid as an expression any more (use '# type:' comment instead)

I suspect that mypy is right and the PEP didn't catch up to the change of mind in the flurry of activity right before acceptance.

Since it's provisional I'd like to change the PEP to disallow this.

At the same time at runtime I think it should either fail loudly or work, not silently return an uninitialized instance, so typing.py also needs to be fixed.

Thanks for the report!
msg262477 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-03-26 00:27
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 Node[T]() and Node[int]() 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.
msg262861 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2016-04-04 18:05
This is fixed upstream (https://github.com/python/typing/commit/8c6aaf30751fec28f1a7e467139ae23c9cc30c81). I'm keeping this open until I've merged typing.py into CPython 3.5 and 3.6.
msg262910 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2016-04-05 15:35
New changeset be3c4151d9bf by Guido van Rossum in branch '3.5':
Many changes from the upstream repo (https://github.com/python/typing).
https://hg.python.org/cpython/rev/be3c4151d9bf
History
Date User Action Args
2016-04-05 15:37:50gvanrossumsetstatus: open -> closed
resolution: fixed
2016-04-05 15:35:48python-devsetnosy: + python-dev
messages: + msg262910
2016-04-04 18:05:54gvanrossumsetmessages: + msg262861
2016-03-26 00:27:53gvanrossumsetmessages: + msg262477
2016-03-25 23:51:05vstinnersettitle: Specialized sub-classes of Generic never call __init__ -> typing: Specialized sub-classes of Generic never call __init__
2016-03-23 20:41:58gvanrossumsetmessages: + msg262306
2016-03-23 11:23:07SilentGhostsetnosy: + gvanrossum
2016-02-19 11:52:22Kai Wohlfahrtcreate