How to restrict setting an attribute outside of constructor?

ozgur picture ozgur · Jun 7, 2012 · Viewed 8.6k times · Source

I want to forbid further assignments on some attributes of a class after it was initialized. For instance; no one can explicitly assign any value to 'ssn' (social security number) property after the Person instance 'p' has been initialized. _setattr_ is also being called while assigning the value inside _init_ method, thus it is not what I want. I'd like to restrict only further assignments. How can I achieve that?

class Person(object):
    def __init__(self, name, ssn):
        self.name = name
        self._ssn = ssn

    def __setattr__(self, name, value):
        if name == '_ssn':
            raise AttributeError('Denied.')
        else:
            object.__setattr__(self, name, value)

>> p = Person('Ozgur', '1234')
>> AttributeError: Denied.

Answer

Sven Marnach picture Sven Marnach · Jun 7, 2012

The usual way is to use a "private" attribute starting with an underscore, and a read-only property for public access:

import operator

class Person(object):
    def __init__(self, name, ssn):
        self.name = name
        self._ssn = ssn
    ssn = property(operator.attrgetter("_ssn"))

Note that this does not really hinder anybody to change the attribute _ssn, but the leading _ documents that the attribute is private.