howto prevent class variable assignment

Peter Otten __peter__ at web.de
Sun Feb 1 11:53:34 EST 2004


Uwe Mayer wrote:

> when an instance variable of a class is not found, python tries to fall
> back to the class variable.
> I want to use that feature to provide default settings for a class which
> can be overwritten by assignments to variables with the same name.
> 
> This quickly becomes difficult to handle when you get confused wether your
> assignment was made to a class variable or an instance variable. I
> therefore want to prevent write access to class variables. How do I do

The sane way would be to copy mutable defaults in __init__().

> that?
> 
> Here some example code:
> 
>>>> class A(object):
> ...   cInt = 5
> ...   cList = [1,2,3]
> ...   def __init__(self):
> ...     self.cInt = 6
> ...
>>>> a = A()
>>>> a.cInt
> 6
>>>> a.__class__.cInt
> 5
> 
>>>> a.cList[2] = 5   #<-- prevent this

I fear this is *hard* as you are just changing an instance of a mutable
class. Maybe you could write a general readonly wrapper?

>>>> a.cList
> [1, 2, 5]
> 
>>>> a.cInt = 42       #<-- allow this
>>>> a.cInt
> 42
>>>> a.__class__.cInt
> 5
> 
>>>>A.cInt = 10       #<-- prevent this
> 
> I tried to overwrite __setattr__(self, name, value) method, but this is
> only called if I call it on an instance, i.e.
> 
>>>> a.cInt = 5
> 
> but not when I call it on the class:
> 
>>>> A.cInt = 10
> 
> 
> Can anyone give me some pointers or suggentions how to handle this?

A is an instance of its metaclass, so you have to devise a way to prevent
write access for metaclass instances.

Below is an example that uses the "sealed" attribute to prevent further
write access when you are done defining the class:

>>> class Type(type):
...     def __setattr__(self, name, value):
...             if hasattr(self, "sealed"):
...                     raise Exception("Attempt to set class att                                 
ribute")
...             type.__setattr__(self, name, value)
...
>>> class Test:
...     __metaclass__ = Type
...     x = 123
...     y = 456
...
>>> Test.x = 111
>>> Test.sealed = True # class attributes can no longer be rebound (más o
menos)
>>> Test.x = 222
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 4, in __setattr__
Exception: Attempt to set class attribute
>>> t = Test()
>>> t.x = 789 # instance attributes behave just normal
>>>

Again, this will not prevent changing a mutable instance, e. g. setting a
list item. Your time is probably better spend on writing a good test suite
for your app.

Peter






More information about the Python-list mailing list