views:

213

answers:

4

I use 'property' to ensure that changes to an objects instance variables are wrapped by methods where I need to.

What about when an instance has an variable that logically should not be changed? Eg, if I'm making a class for a Process, each Process instance should have a pid attribute that will frequently be accessed but should not be changed.

What's the most Pythonic way to handle someone attempting to modify that instance variable?

  • Simply trust the user not to try and change something they shouldn't?

  • Use property but raise an exception if the instance variable is changed?

  • Something else?

+1  A: 

Maybe you can override __setattr__? In the line of,

def __setattr__(self, name, value):
    if self.__dict__.has_key(name):
        raise TypeError, 'value is read only'
    self.__dict__[name] = value
kotlinski
+5  A: 

Prepend name of the variable with __, and create read-only property, Python will take care of exceptions, and variable itself will be protected from accidental overwrite.

class foo(object):
    def __init__(self, bar):
        self.__bar = bar

    @property
    def bar(self):
        return self.__bar

f = foo('bar')
f.bar         # => bar
f.bar = 'baz' # AttributeError; would have to use f._foo__bar
PiotrLegnica
In last two lines, you mean "f.foo" and "f.foo='baz'", right?
Ivan Vučica
Yeah, I mixed up variable names. Already corrected.
PiotrLegnica
I find the name-mangled "private" attributes to be more trouble than they're worth. A single underscore will make subclassing easier while still communicating "don't touch this" to users.
Ants Aasma
The problem with non-mangled names is that they can be accidentally overwritten in subclasses. Since those fields are not part of your public API, the API clients shouldn't be required to be aware of the names of your "private" fields, but they have to do so anyway because otherwise they risk breaking your class. And, of course, if, in a new version of the class, you introduce a new field, you can break existing clients that have subclasses which already use the same field name. Mangled version still has all those problems, but it does reduce the likelihood a lot.
Pavel Minaev
+3  A: 

Simply trusting the user is not necessarily a bad thing; if you are just writing a quick Python program to be used once and thrown away, you might very well just trust that the user not alter the pid field.

IMHO the most Pythonic way to enforce the read-only field is to use a property that raises an exception on an attempt to set the field.

So, IMHO you have good instincts about this stuff.

steveha
+1  A: 

Simply use a property and a hidden attribute (prefixed with one underscore).

Simple properties are read-only!

>>> class Test (object):
...  @property
...  def bar(self):
...   return self._bar
... 
>>> t = Test()
>>> t._bar = 2
>>> t.bar
2
>>> t.bar = 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Hiding with double underscore is not used to hide the implementation, but to make sure you don't collide with a subclass' attributes; consider a mixin for example, it has to be very careful!

If you just want to hide the attribute, use a single underscore. And as you see there is no extra magic to add -- if you don't define a set function, your property is just as read-only as the return value of a method.

kaizer.se