Skip to content

Inheritance issues with generic collections #202

Closed

Description

@bintoro

I have a problem with how __extra__ is currently inherited:

>>> class CustomMapping(typing.Mapping): ...
... 
>>> issubclass(dict, CustomMapping)
True
>>> class CustomDict(typing.Dict): ...
... 
>>> issubclass(dict, CustomDict)
True

This can't be right.

My initial impression is that __extra__ should only be propagated on parameterization, not when subclassing, and that the concrete types List, Dict, etc. should have their own extras (list, dict, and so on). Thoughts? A tentative patch is here.

Another thing: The module distributed on PyPI still has the issue where a generic doesn't include itself in the subtype's MRO during parameterization. This was fixed for Python 3.5.1 in aab2c59. It would be great if we could get a more recent revision on PyPI as well.

3.5.1:

>>> issubclass(Iterable[int], Iterable)
True

3.5.0:

>>> issubclass(Iterable[int], Iterable)
False

And finally, a question: The collections ABC replacements do not provide the abstract (or any other) methods of the originals. In particular, Iterable is technically not abstract at all. Is this intentional or just a temporary state of affairs?

Activity

  1. gvanrossum commented on Apr 16, 2016

    @gvanrossum
    Member
    • I'll look over your patch.
    • I'll see if I can release a 3.5.1 version -- it looks like 3.5.2 is still a while away.
    • It's probably an oversight that Iterable isn't abstract; or perhaps there was a technical issue.
  2. gvanrossum commented on Apr 16, 2016

    @gvanrossum
    Member
  3. bintoro commented on Apr 16, 2016

    @bintoro
    ContributorAuthor

    Updated the typing gpackage to 3.5.1.

    Thanks!

    As for the abstract methods, adding __iter__ to Iterable seems to have no ill effects.

    Container, Awaitable, and AsyncIterable and their derivatives are also affected — in other words everything that doesn't inherit from Sized or Hashable.

    One option is to just copy everything over during class construction:

     class GenericMeta(TypingMeta, abc.ABCMeta):
    
         def __new__(cls, name, bases, namespace,
                     tvars=None, args=None, origin=None, extra=None):
    +        if extra and origin is None:
    +            for methodname in getattr(extra, '__abstractmethods__', ()):
    +                if methodname in extra.__dict__:
    +                    namespace.setdefault(methodname, extra.__dict__[methodname])
    +
             self = super().__new__(cls, name, bases, namespace, _root=True)
  4. gvanrossum commented on Apr 18, 2016

    @gvanrossum
    Member

    I would like to go slow here. I have other priorities (see #203 (comment)). I will eventually get to this but I'm not sure I want to rush anything into 3.5.2 beyond what's already on deck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions