Skip to content

Instantly share code, notes, and snippets.

@lemon24
Last active August 17, 2020 13:27
Show Gist options
  • Save lemon24/d1f00f5f3e02f879e2c280fcdb438f87 to your computer and use it in GitHub Desktop.
Save lemon24/d1f00f5f3e02f879e2c280fcdb438f87 to your computer and use it in GitHub Desktop.
None-like singleton in Python (mypy-compatible)
"""
None-like singleton in Python (mypy-compatible).
https://github.com/lemon24/reader/issues/177#issuecomment-674786498
"""
from typing import Union, cast
class NoValueType:
def __new__(cls) -> 'NoValueType':
return NoValue
def __repr__(self) -> str:
return 'NoValue'
def __bool__(self) -> bool:
# to prevent "if thing" when "if thing is False" was meant;
raise TypeError("cannot use NoValue in boolean context")
NoValue = cast(NoValueType, object.__new__(NoValueType))
assert NoValueType() is NoValue
"""
# alternative way to make a singleton based on https://stackoverflow.com/a/6798042
from typing import Dict, Any
class Singleton(type):
_instances: Dict['Singleton', 'Singleton'] = {}
def __call__(cls, *args: Any, **kwargs: Any) -> 'Singleton':
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class NoValueType(metaclass=Singleton):
... # repr etc.
"""
# we could define a MyOptional[T] == Union[NoValueType, T], but it's too complicated
one: Union[NoValueType, str] = 'aaa'
two: Union[NoValueType, str] = NoValue
for maybe_str in one, two:
# sadly, mypy can't understand "maybe_str is NoValue", like it does for None
if isinstance(maybe_str, str):
print(maybe_str.lower())
else:
print(repr(maybe_str))
# error: Item "NoValueType" of "Union[NoValueType, str]" has no attribute "lower"
maybe_str.lower()
aaa: Union[NoValueType, bool] = True
bbb: Union[NoValueType, bool] = NoValue
def negate(a: bool) -> bool:
return not a
for maybe_bool in aaa, bbb:
if isinstance(maybe_bool, bool):
print(negate(maybe_bool))
else:
print(repr(maybe_bool))
# error: Argument 1 to "negate" has incompatible type "Union[NoValueType, bool]"; expected "bool"
negate(maybe_bool)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment