Well, I fixed the problem with class methods in one line. :-)

https://github.com/gvanrossum/cpython/commit/ce78557085b0755ae3e4b1bf6080930a8080756e

On Mon, Jan 27, 2020 at 5:48 PM Guido van Rossum <guido@python.org> wrote:
On Mon, Jan 27, 2020 at 4:32 PM I wrote:
Okay -- I have now moved to a prototype written in C, which you can see emerge here:


I don't think there's much more that we can learn from Python prototypes at this point -- so many details are different.

I've now got this branch to the point where it defines a GenericAlias type object in C that does (mostly?) correct pass-through and allows subclassing.

I need a breather so if you want to contribute a C implementation of my __repr__ you're welcome to give it a try.

This also provides a (rare!) example of a situation where type(t) and t.__class__ are legitimately different!

>>> t = list[int]
>>> type(t)
<class 'GenericAlias'>
>>> t.__class__
<class 'type'>
>>>
 
On Mon, Jan 27, 2020 at 2:37 PM Ethan Smith <ethan@ethanhs.me> wrote:
Hi Guido,

I actually was playing around with how to implement this yesterday, and I put together the attached as an implementation. I realized that simply passing attributes through via `__getattr__` likely won't work, as class methods and variables won't be passed through correctly, so in you example, I believe dict_str_pair.from_keys(range(10)) will fail.

Oh, this fails in my C implementation:

>>> t = dict[int, str]
>>> t.fromkeys(range(10))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor 'fromkeys' for type 'dict' needs a type, not a 'range' as arg 2
>>> dict.fromkeys(range(10))
{0: None, 1: None, 2: None, 3: None, 4: None, 5: None, 6: None, 7: None, 8: None, 9: None}
>>>

But I don't think your solution would help:
 
That is why I created an ad-hoc subclass of the subscripted type, so that it will inherit all of that, and we can just override what we need. Perhaps there is a simpler solution to solve this problem that I am unaware of.

I don't know, but I don't think your solution is right: it doesn't erase the generics for the created instance. PEP 585 specifies that the *class* produced by list[int] has to know its __origin__ and __parameters__, but it also specifies that the *instance* produced by calling that -- i.e., a = list[int]() -- should *not* know that it was created from a parameterized class -- its type() and .__class__ should just be list. But in your case:

$ python3 -i pep585.py
...
>>> t = list[int]  # That is your clever subclass of list
>>> t
list[int]
>>> a = t()
>>> a
[]
>>> a.__class__  # Expect list, got list[int]
list[int]
>>> type(a)  # Expect list, got error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type.__new__() takes exactly 3 arguments (1 given)
>>>
 
I copied your repr since it was better than the one I threw together :)

Thanks -- now I need to rewrite it in C. :-) Or if you want to contribute a C implementation you're welcome to give it a try.

--
--Guido van Rossum (python.org/~guido)


--
--Guido van Rossum (python.org/~guido)
Pronouns: he/him (why is my pronoun here?)