kakyo
kakyo

Reputation: 11590

python: Create read-only properties that can be written by self using assignment

I tried to create a read-only property by not providing a setter. But seems that in the same class I cannot write to that property attribute either.

Is this how a read-only property is supposed to work? I do need to modify it in its class but do not want it to be written by other classes. That's why I prefer being able to:

class MyClass(object)
    def __init__(self):
        self.myAttrib = None

    def getx(self):
        return self.myAttrib

    myAttrib = property(getx, "I'm the read-only property.")

    def MyMethod(self):
        self.myAttrib = myValue

Is there a way to achieve that?

Upvotes: 1

Views: 163

Answers (1)

BrenBarn
BrenBarn

Reputation: 251368

Yes, that is how it's supposed to work. Read-only means read-only, not "readable by some classes and writable by others".

It is probably possible to make it so it is writable only by its class, but you should think about why you want this. In general Python is not geared towards this kind of design. You should just document that the attribute is private, and perhaps give it a name that starts with an underscore (one underscore, not two). This makes it clear that if someone else writes code that messes with it, they're on their own, and then if they do that and something goes wrong, it's their own fault. There is little real benefit to enforcing the class-private access.

Note, though, that your code has some errors anyway, as you're not using property correctly. You're giving the property the same name as the underlying attribute it's accessing. If your property is called myAttrib, its getter/setter should get/set an attribute with a different name. The property's name is the name of the property itself, not the hidden attribute where it stores the value it gets/sets. So more like:

def __init__(self):
    self._myAttrib = "I'm the read-only property."

def getx(self):
    return self._myAttrib

myAttrib = property(getx)

Now myAttrib is a property that provides read access to the underlying attribute _myAttrib. That's how properties work in Python. Note also that you don't pass the value "I'm the read-only property." to property, you set it directly on the underlying attribute.

If you wanted, you could do a property like this and then set _myAttrib directly in your class's code. This would be something like what you seem to want: it would let you set the value, but other code using the property (and not the "secret" _myAttrib) would not be able to set it.

However, this too is something you should reconsider. There is no real point to defining a trivial getter like this. It is simpler to just name the attribute _myAttrib and read its value directly, and document that that value should not be changed. The point of properties is not to provide enforcement of protocols about who should and shouldn't access attributes; the point is to allow programmatic calculation or manipulation of values when they are get/set (so that, e.g., setting a property also updates other linked attributes on the object).

Upvotes: 7

Related Questions