Add NewType() to PEP 484.
This commit is contained in:
parent
ae2bd4d5ca
commit
7596c54962
65
pep-0484.txt
65
pep-0484.txt
|
@ -1173,6 +1173,68 @@ checker should blindly believe the programmer. Also, casts can be used
|
|||
in expressions, while type comments only apply to assignments.
|
||||
|
||||
|
||||
NewType helper function
|
||||
-----------------------
|
||||
|
||||
There are also situations where a programmer might want to avoid logical
|
||||
errors by creating simple classes. For example::
|
||||
|
||||
class UserId(int):
|
||||
pass
|
||||
|
||||
get_by_user_id(user_id: UserId):
|
||||
...
|
||||
|
||||
However, this approach introduces a runtime overhead. To avoid this,
|
||||
``typing.py`` provides a helper function ``NewType`` that creates
|
||||
simple unique types with almost zero runtime overhead. For a static type
|
||||
checker ``Derived = NewType('Derived', Base)`` is roughly equivalent
|
||||
to a definition::
|
||||
|
||||
class Derived(Base):
|
||||
def __init__(self, _x: Base) -> None:
|
||||
...
|
||||
|
||||
While at runtime, ``NewType('Derived', Base)`` returns a dummy function
|
||||
that simply returns its argument. Type checkers require explicit casts
|
||||
from ``int`` where ``UserId`` is expected, while implicitly casting
|
||||
from ``UserId`` where ``int`` is expected. Examples::
|
||||
|
||||
UserId = NewType('UserId', int)
|
||||
|
||||
def name_by_id(user_id: UserId) -> str:
|
||||
...
|
||||
|
||||
UserId('user') # Fails type check
|
||||
|
||||
name_by_id(42) # Fails type check
|
||||
name_by_id(UserId(42)) # OK
|
||||
|
||||
num = UserId(5) + 1 # type: int
|
||||
|
||||
``NewType`` accepts only one argument that shoud be a proper class,
|
||||
i.e., not a type construct like ``Union``, etc. The function returned
|
||||
by ``NewType`` accepts only one argument; this is equivalent to supporting
|
||||
only one constructor accepting an instance of the base class (see above).
|
||||
Example::
|
||||
|
||||
class PacketId:
|
||||
def __init__(self, major: int, minor: int) -> None:
|
||||
self._major = major
|
||||
self._minor = minor
|
||||
|
||||
TcpPacketId = NewType('TcpPacketId', PacketId)
|
||||
|
||||
packet = PacketId(100, 100)
|
||||
tcp_packet = TcpPacketId(packet) # OK
|
||||
|
||||
tcp_packet = TcpPacketId(127, 0) # Fails in type checker and at runtime
|
||||
|
||||
Both ``isinstance`` and ``issubclass``, as well as subclassing will fail
|
||||
for ``NewType('Derived', Base)`` since function objects don't support
|
||||
these operations.
|
||||
|
||||
|
||||
Stub Files
|
||||
==========
|
||||
|
||||
|
@ -1562,6 +1624,9 @@ Convenience definitions:
|
|||
This is useful to declare the types of the fields of a named tuple
|
||||
type.
|
||||
|
||||
* NewType, used to create unique types with little runtime overhead
|
||||
``UserId = NewType('UserId', int)``
|
||||
|
||||
* cast(), described earlier
|
||||
|
||||
* @no_type_check, a decorator to disable type checking per class or
|
||||
|
|
Loading…
Reference in New Issue