Skip to content

Instantly share code, notes, and snippets.

@nfitzen
Last active December 22, 2021 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nfitzen/d3f9aaf17acda34c37452b528d060fa8 to your computer and use it in GitHub Desktop.
Save nfitzen/d3f9aaf17acda34c37452b528d060fa8 to your computer and use it in GitHub Desktop.
A Python decorator that makes a class immutable after initialization.
# SPDX-License-Identifier: MIT
# SPDX-FileNotice: The Expat/MIT variant is the one without the "next paragraph" parenthetical but with the "MIT License" header.
# Copyright (C) 2021 nfitzen <https://github.com/nfitzen>
# Note that this code is very basic and likely buggy, as with everything I
# write. Specifically, the help message is a bit weird and slightly inaccurate.
import functools
from typing import Any
__all__ = (
"FrozenInstanceError",
"frozen",
)
class FrozenInstanceError(AttributeError):
pass
def frozen(cls: type) -> type:
"""Freezes an object after calling its __init__ method."""
def setat(self, name: str, value: Any) -> None:
"""Raises FrozenInstanceError after initialization."""
if getattr(self, "__is_frozen__", False):
raise FrozenInstanceError
object.__setattr__(self, name, value)
def delat(self, name: str) -> None:
"""Raises FrozenInstanceError after initialization."""
if getattr(self, "__is_frozen__", False):
raise FrozenInstanceError
object.__delattr__(self, name)
@functools.wraps(cls.__init__)
def init(self, *args, **kwargs):
return_val = self.__frozen_init__(*args, **kwargs)
self.__is_frozen__ = True
return return_val
orig_init = cls.__init__
setattr(cls, "__init__", init)
setattr(cls, "__frozen_init__", orig_init)
setattr(cls, "__delattr__", delat)
setattr(cls, "__setattr__", setat)
return cls
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment