[Python-ideas] Adding Type[C] to PEP 484

Guido van Rossum guido at python.org
Fri May 13 15:31:04 EDT 2016


I've got another proposed update to PEP 484 ready. There was previously
some discussion on python-ideas (Bcc'ed for closure) and quite a bit on the
typing issue tracker: https://github.com/python/typing/issues/107

I've worked all that into a patch for PEP 484:
https://github.com/python/typing/pull/218

Once we're okay with that I will work on getting the implementation ready
in time for Python 3.5.2.

Here's the added text:

Meta-types
----------

A meta-type can be used to indicate a value that is itself a class
object that is a subclass of a given class.  It is spelled as
``Type[C]`` where ``C`` is a class.  To clarify: while ``C`` (when
used as an annotation) refers to instances of class ``C``, ``Type[C]``
refers to *subclasses* of ``C``.  (This is a similar distinction as
between ``object`` and ``type``.)

For example, suppose we have the following classes::

  class User: ...  # Abstract base for User classes
  class BasicUser(User): ...
  class ProUser(User): ...
  class TeamUser(User): ...

And suppose we have a function that creates an instance of one of
these classes if you pass it a class object::

  def new_user(user_class):
      user = user_class()
      # (Here we could write the user object to a database)
      return user

Without ``Type[]`` the best we could do to annotate ``new_user()``
would be::

  def new_user(user_class: type) -> User:
      ...

However using ``Type[]`` and a type variable with an upper bound we
can do much better::

  U = TypeVar('U', bound=User)
  def new_user(user_class: Type[U]) -> U:
      ...

Now when we call ``new_user()`` with a specific subclass of ``User`` a
type checker will infer the correct type of the result::

  joe = new_user(BasicUser)  # Inferred type is BasicUser

At runtime the value corresponding to ``Type[C]`` must be an actual
class object that's a subtype of ``C``, not a special form.  IOW, in
the above example calling e.g. ``new_user(Union[BasicUser, ProUser])``
is not allowed.

There are some concerns with this feature: for example when
``new_user()`` calls ``user_class()`` this implies that all subclasses
of ``User`` must support this in their constructor signature.  However
this is not unique to ``Type[]``: class methods have similar concerns.
A type checker ought to flag violations of such assumptions, but by
default constructor calls that match the constructor signature in the
indicated base class (``User`` in the example above) should be
allowed.  A program containing a complex or extensible class hierarchy
might also handle this by using a factory class method.

Plain ``Type`` without brackets is equivalent to using ``type`` (the
root of Python's metaclass hierarchy).  This equivalence also
motivates the name, ``Type``, as opposed to alternatives like
``Class`` or ``SubType``, which were proposed while this feature was
under discussion; this is similar to the relationship between
e.g. ``List`` and ``list``.


-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160513/74558d17/attachment.html>


More information about the Python-ideas mailing list