2

I've been using the following to "freeze" class instances in Python so that if I unwittingly define a new instance variable it brings up an error rather than just letting me do so.

class FrozenClass(object):
        __isfrozen = False

        def __setattr__(self, key, value):
            if self.__isfrozen and key not in dir(self):
                raise TypeError( "%r is a frozen class" % self )

            object.__setattr__(self, key, value)

        def _freeze(self):
            self.__isfrozen = True

        ## so that if you're inheriting a frozen class you can unfreeze it 
        def _unfreeze(self):
            self.__isfrozen = False

Which works as so:

>>> class Foo(FrozenClass):
...     def __init__(self):
...             self.a = 1
...             self._freeze()
...
>>> myInstance = Foo()
>>> myInstance.A = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/XXX/Desktop/Git/functions/FrozenClass.py", line 6, in __setattr__
    raise TypeError( "%r is a frozen class" % self )
TypeError: <__main__.Foo object at 0x10075c4e0> is a frozen class
>>>

However I've been working with a global data object which I've made static and it doesn't work. I've tried playing around with it but to no avail. Here it is as it currently stands:

## doesn't currently work. Not sure. 
class FrozenStaticClass(object):
    __isfrozen = False

    def __setattr__(cls, key, value):
        if cls.__isfrozen and key not in dir(cls):
            raise TypeError( "%r is a frozen class" % cls )

        object.__setattr__(cls, key, value)

    @classmethod
    def _freeze(cls):
        cls.__isfrozen = True

    @classmethod
    def _unfreeze(cls):
        cls.__isfrozen = False

How do I get it to freeze static classes?

Edit: @volcano suggested using slots but it doesn't seem to work for class variables.

m4p85r
  • 402
  • 2
  • 17
  • Why don't you just inherit from https://docs.python.org/3.4/library/collections.html#collections.namedtuple? – volcano Apr 17 '17 at 22:45
  • As in make the parent of the static class to be a named tuple? – m4p85r Apr 17 '17 at 22:47
  • @ashgetstazered Your correct. that's what he means when he says "inherit". – Christian Dean Apr 17 '17 at 22:50
  • 1
    I think what you are looking for are *slots*. See [this discussion](http://stackoverflow.com/questions/472000/usage-of-slots) – volcano Apr 17 '17 at 22:51
  • @volcano if I inherit a named tuple then I won't be able to modify the valid variables as it would then make the entire class completely immutable after the initialisation? I don't want this. I just want to throw an error if I create a new class variable outside of the class code but I still want to be able to edit it. – m4p85r Apr 17 '17 at 22:55
  • See my next comment - I posted it as answer, but SO converted it to comment. – volcano Apr 17 '17 at 22:57
  • Cheers, I can slots to work for an instance case, but when I try use it in a static class I get the error: ValueError: 'a' in __slots__ conflicts with class variable. If you could post up an extremely short example with a @classmethod I'll accept it. – m4p85r Apr 17 '17 at 23:05
  • @volcano in that [dicussion](http://stackoverflow.com/questions/472000/usage-of-slots) it says to "Avoid [slots] if you insist on providing default values via class attributes for instance variables.". While I'm not instantiating anything I think this is because class variables conflict with slots. – m4p85r Apr 17 '17 at 23:30

0 Answers0