-
Notifications
You must be signed in to change notification settings - Fork 262
Add text about Type[C]. #218
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
This addresses #107 (but it doen't close it because the issue also calls for an implementation in typing.py).
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -861,6 +861,72 @@ allow all operations on it, and a value of type ``Any`` can be assigned | |
to a variable (or used as a return value) of a more constrained type. | ||
|
||
|
||
Meta-types | ||
---------- | ||
|
||
A meta-type can be used to indicate a value that is itself a class | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following the comment above, I would replace this by "An additional fundamental building block can be used to indicate a value that..." Putting registry = [] # type: List[Tuple[int, Type[FrameworkBase]]] |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would remove "At runtime". Just "The value corresponding to..." |
||
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 was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe replace here "is not allowed" by "is rejected by the type checker"? Calling |
||
|
||
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``. | ||
|
||
|
||
Version and platform checking | ||
----------------------------- | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think "Meta-types" is not a good name for this section for four reasons:
Type[C]
has normal semantics of type: This is just a set of objects that respondTrue
toissubclass(objc, C)
.Type[C]
or byABCMeta
meta-types, then how are we supposed to call annotations of values that are metaclasses (byType[ABCMeta]
for example)? Meta-meta-types? :-)