How does __setattr__ work with class attributes?
<p>I am trying to understand how exactly __setattr__ works with class attributes. This question came about when I had attempted to override __setattr__ to prevent attributes from being written to in a simple class.</p>

<p>My first attempt used instance level attributes as follows:</p>

<pre><code>class SampleClass(object):

    def __init__(self):
        self.PublicAttribute1 = "attribute"

    def __setattr__(self, key, value):
        raise Exception("Attribute is Read-Only")
</code></pre>

<p>I had originally thought that only external attempts to set the attribute would throw an error, but even the statement inside the __init__ caused the exception to be thrown.</p>

<p>Later I ended up finding another way to do this, while attempting to solve a different problem. What I ended up with was:</p>

<pre><code>class SampleClass(object):
    PublicAttribute1 = "attribute"

    def __setattr__(self, key, value):
        raise Exception("Attribute is Read-Only")
</code></pre>

<p>I expected to get the same result, but to my surpirse I was able to set the class attribute while preventing changes from being made after the initial declaration. </p>

<p>I don't understand why this works though. I know it has to do with class vs. instance variables. My theory is that using __setattr__ on a class variable will create an instance variable of the same name, since I believe I think I have seen this behavior before, but I am not sure.</p>

<p>Can anyone explain exactly what is happening here?</p>

<p><code>__setattr__</code> is only invoked on <em>instances</em> of a class and not the actual class itself. However, the class is still an object, so when setting the attribute of the class the <code>__setattr__</code> of the class of the class is invoked. </p>

<p>To change how attributes are set on classes you need to look into meta-classes. Metaclasses are overkill for almost any application, and can get confusing very easily. And trying to make a user-defined class/object read-only is normally a bad idea. That said, here is a simple example. </p>

<pre><code>&gt;&gt;&gt; class SampleMetaclass(type): # type as parent, not object
...     def __setattr__(self, name, value):
...         raise AttributeError("Class is read-only")
... 
&gt;&gt;&gt; class SampleClass(metaclass=SampleMetaclass):
...     def __setattr__(self, name, value):
...         raise AttributeError("Instance is read-only")
... 
&gt;&gt;&gt; SampleClass.attr = 1
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 3, in __setattr__
AttributeError: Class is read-only
&gt;&gt;&gt; s = SampleClass()
&gt;&gt;&gt; s.attr = 1
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 3, in __setattr__
AttributeError: Instance is read-only
</code></pre>

python