Skip to content

Instantly share code, notes, and snippets.

@tzaffi
Last active April 29, 2024 02:27
Show Gist options
  • Save tzaffi/69c213cb65bf20720208303942d01ac2 to your computer and use it in GitHub Desktop.
Save tzaffi/69c213cb65bf20720208303942d01ac2 to your computer and use it in GitHub Desktop.
How to create "immutable" constants in Python
class ContainerOfConstants(type):
def __new__(metacls, name, bases, namespace):
namespace["_const_values"] = frozenset(
value
for key, value in namespace.items()
if not key.startswith("_")
)
cls = super().__new__(metacls, name, bases, namespace)
cls._initializing = True
return cls
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
cls._initializing = False
cls._frozen = True
def __setattr__(cls, key, value):
if getattr(cls, "_frozen", False) and not getattr(cls, "_initializing", False):
if hasattr(cls, key):
raise AttributeError(f"{key} is immutable and cannot be changed")
super().__setattr__(key, value)
def __contains__(cls, item):
return item in cls._const_values
class Stuff(metaclass=ContainerOfConstants):
FIRST_CONST = 42
SECOND_CONST = 17
THIRD_CONST = 105
ANOTHER_CONST = -11
####### test it out #######
try:
Stuff.FIRST_CONST = 100
except AttributeError as e:
print(e)
print(Stuff.THIRD_CONST)
print(Stuff._const_values)
print(42 in Stuff)
print(999 in Stuff)
Stuff._const_values.add(999)
####### stdout #######
FIRST_CONST is immutable and cannot be changed
105
frozenset({17, 42, -11, 105})
True
False
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[15], line 10
8 print(42 in Stuff)
9 print(999 in Stuff)
---> 10 Stuff._const_values.add(999)
AttributeError: 'frozenset' object has no attribute 'add'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment