decorator to prevent adding attributes to class?

Robert Bossy Robert.Bossy at jouy.inra.fr
Fri Jul 11 12:38:58 EDT 2008


Michele Simionato wrote:
> This article could give you same idea (it is doing the opposite,
> warning you
> if an attribute is overridden):
> http://stacktrace.it/articoli/2008/06/i-pericoli-della-programmazione-con-i-mixin1/
>
> There is also a recipe that does exactly what you want by means of a
> metaclass:
> http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/252158
> It is so short I can write it down here:
> # requires Python 2.2+
>
> def frozen(set):
>     "Raise an error when trying to set an undeclared name."
>     def set_attr(self,name,value):
>         if hasattr(self,name):
>             set(self,name,value)
>         else:
>             raise AttributeError("You cannot add attributes to %s" %
> self)
>     return set_attr
>
> class Frozen(object):
>     """Subclasses of Frozen are frozen, i.e. it is impossibile to add
>      new attributes to them and their instances."""
>     __setattr__=frozen(object.__setattr__)
>     class __metaclass__(type):
>         __setattr__=frozen(type.__setattr__)
>   
I don't get it. Why use a metaclass? Wouldn't the following be the same, 
but easier to grasp:

class Frozen(object):
    def __setattr__(self, name, value):
       if not hasattr(self, name):
          raise AttributeError, "cannot add attributes to %s" % self
       object.__setattr__(self, name, value)

Btw, the main drawback with Frozen is that it will not allow to set any 
new attributes even inside __init__.


Some people would advise to use __slots__:
        http://docs.python.org/ref/slots.html#l2h-222
Some other people would advise NOT to use __slots__:
        http://groups.google.com/group/comp.lang.python/msg/0f2e859b9c002b28



Personally, if I must absolutely, I'd go for explicitely freeze the 
object at the end of __init__:

class Freezeable(object):
    def freeze(self):
       self._frozen = None

    def __setattr__(self, name, value):
       if hasattr(self, '_frozen') and not hasattr(self, name):
          raise AttributeError
       object.__setattr__(self, name, value)


class Foo(Freezeable):
    def __init__(self):
       self.bar = 42
       self.freeze() # ok, we set all variables, no more from here


x = Foo()
print x.bar
x.bar = -42
print x.bar
x.baz = "OMG! A typo!"


Cheers,
RB



More information about the Python-list mailing list