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>The <code>__setattr__</code> method defined in a class is only called for attribute assignments on <em>istances</em> of the class. It is not called for class variables, since they're not being assigned on an instance of the class with the method.</p>

<p>Of course, classes are instances too. They're instances of <code>type</code> (or a custom metaclass, usually a subclass of <code>type</code>). So if you want to prevent class variable creation, you need to create a metaclass with a <code>__setattr__</code> method.</p>

<p>But that's not really what you need to make your class do what you want. To just get a read-only attribute that can only be written once (in the <code>__init__</code> method), you can probably get by with some simpler logic. One approach is to set another attribute at the end of the <code>__init__</code> method, which tells <code>__setattr__</code> to lock down assignments after it is set:</p>

<pre><code>class Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self._initialized = True

    def __setattr__(self, name, value):
        if self.__dict__.get('_initialized'):
            raise Exception("Attribute is Read-Only")
        super().__setattr__(name, value)
</code></pre>

<p>Another option would be to use <code>property</code> descriptors for the read-only attributes and store the real values in "private" variables that can be assigned to normally. You'd not use <code>__setattr__</code> in this version:</p>

<pre><code>class Foo():
    def __init__(a, b):
        self._a = a
        self._b = b

    @property
    def a(self):
        return self._a

    @property
    def b(self):
        return self._b
</code></pre>

python