Last active
January 3, 2022 00:12
-
-
Save misja/2a7ab71f6346c5c19382412627ddf34e to your computer and use it in GitHub Desktop.
Python None is an object (and a singleton)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# None is of type NoneType | |
print(f"{None} is of type", type(None)) | |
# Each object contains a reference to its class, | |
# let's use this to create a new instance of NoneType | |
NewNone = None.__class__() | |
# NoneType is a *singleton*, so should be equal | |
assert NewNone is None | |
# Can we set attributes on None? | |
try: | |
None.ok = True # can't set attributes on None | |
except AttributeError as e: | |
print(f"Can't set attribute on {None}:", e) | |
# Let's emulate NoneType, a singleton! | |
class EmptyType: | |
__slots__ = () # no declared instance attributes permitted | |
def __new__(cls, *args, **kwargs): | |
if not hasattr(cls, "_instance"): | |
cls._instance = super().__new__(cls, *args, **kwargs) | |
return cls._instance # will be 'self' in instance context | |
def __str__(self): | |
return "Empty" | |
__repr__ = __str__ | |
# With None being an instance of NoneType, | |
# so will Empty be an instance of EmptyType | |
Empty = EmptyType() | |
# Empty is of type EmptyType | |
print(f"{Empty} is of type", type(Empty)) | |
# A new instance of EmptyType | |
MyEmpty = EmptyType() # could also have called Empty.__class__() | |
# EmptyType is a *singleton*, should be equal | |
assert MyEmpty is Empty | |
# Can we set attributes on Empty? | |
try: | |
Empty.ok = True # will fail because of __slots__ | |
except AttributeError as e: | |
print(f"Can't set attribute on {Empty}:", e) | |
# But _instance attribute was set, let's modify! | |
try: | |
Empty._instance = "Hey there!" # is read-only | |
except AttributeError as e: | |
print(f"Can't change '_instance' of {Empty}:", e) | |
# NoneType is not a base type (i.e. not subclassable), | |
# but given the above we could do ... | |
class MyNoneType: | |
def __new__(cls, *args, **kwargs): | |
return None # will be 'self' in instance context | |
# New instance! | |
MyNone = MyNoneType() | |
# Will be of type *type*, which we could subclass (if we´d like) | |
print(f"{MyNone} is of type", type(MyNoneType)) | |
# MyNone is a None, hence a *singleton* (NoneType), and should be equal | |
assert MyNone is None | |
# Now also try this with True and False (also objects and singletons) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment