Skip to content

Commit bf22a02

Browse files
author
Guido van Rossum
committed
Add explanation of singletons in unions to PEP484
By Ivan Levkivskyi (python/typing#240).
1 parent a558bf5 commit bf22a02

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

pep-0484.txt

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,66 @@ This is equivalent to::
846846

847847
def handle_employee(e: Optional[Employee] = None) -> None: ...
848848

849+
850+
Support for singleton types in unions
851+
-------------------------------------
852+
853+
A singleton instance is frequently used to mark some special condition,
854+
in particular in situations where ``None`` is also a valid value
855+
for a variable. Example::
856+
857+
_empty = object()
858+
859+
def func(x=_empty):
860+
if x is _empty: # default argument value
861+
return 0
862+
elif x is None: # argument was provided and it's None
863+
return 1
864+
else:
865+
return x * 2
866+
867+
To allow precise typing in such situations, the user should use
868+
the ``Union`` type in conjuction with the ``enum.Enum`` class provided
869+
by the standard library, so that type errors can be caught statically::
870+
871+
from typing import Union
872+
from enum import Enum
873+
874+
class Empty(Enum):
875+
token = 0
876+
_empty = Empty.token
877+
878+
def func(x: Union[int, None, Empty] = _empty) -> int:
879+
880+
boom = x * 42 # This fails type check
881+
882+
if x is _empty:
883+
return 0
884+
elif x is None:
885+
return 1
886+
else: # At this point typechecker knows that x can only have type int
887+
return x * 2
888+
889+
Since the subclasses of ``Enum`` cannot be further subclassed,
890+
the type of variable ``x`` can be statically inferred in all branches
891+
of the above example. The same approach is applicable if more than one
892+
singleton object is needed: one can use an enumeration that has more than
893+
one value::
894+
895+
class Reason(Enum):
896+
timeout = 1
897+
error = 2
898+
899+
def process(response: Union[str, Reason] = '') -> str:
900+
if response is Reason.timeout:
901+
return 'TIMEOUT'
902+
elif response is Reason.error:
903+
return 'ERROR'
904+
else:
905+
# response can be only str, all other possible values exhausted
906+
return 'PROCESSED: ' + response
907+
908+
849909
The ``Any`` type
850910
----------------
851911

0 commit comments

Comments
 (0)