0

I read on many sites that if I want to create a read-only property, I should use the property decorator.

Like this:

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

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

I think this is a good solution if I have just 1-3 read-only properties in a class. But what if I have maybe 10 of these? This would result in 40 extra lines of code only to mark all of them as read-only. In my opinion this does not really fit to Python which is meant to be a language where you do not have to write a big bunch of code to do little things.

Is there really no shorter way to make a property read-only in Python?

Praind
  • 1,551
  • 1
  • 12
  • 25
  • Well, having 10 read-only properties in a class is already a bit unusual. Why do you need this? – Daniel Roseman Jun 29 '18 at 14:41
  • A `property` is just an application of the descriptor protocol. I'm pretty sure you could define your own `readonlyproperty` class, letting you write `a = readonlyproperty("_a")`, `b = readonlyproperty("_b");`, etc, although I'd have to spend some time remembering how that would work. – chepner Jun 29 '18 at 14:43
  • Do you want to make your entire object immutable, or just certain attributes? You could implement `__setattr__` so that it ignores attempts to change certain attributes. – Patrick Haugh Jun 29 '18 at 14:50

1 Answers1

2

At the very least, you could just call property as a function, rather than using it as a decorator. At the same time, you can store the underlying values in a list or dict rather than as separate attributes.

class MyClass(object):
    def __init__(self):
        self._values = [...]

    a = property(lambda self: self._values[0])
    b = property(lambda self: self._values[1])
    # etc

However, a read-only property doesn't really need to store its value in the instance dict; just hard-code the value directly in the getter:

class MyClass(object):

    a = property(lambda self: "foo")
    b = property(lambda self: "bar") 

And then wrap the call to property in another function :)

def constant(value):
    def _(self):
        return value
    return property(_)

class MyClass(object):
    a = constant("foo")
    b = constant("bar")

Here's a pure-Python read-only property, modeled after the example shown at https://docs.python.org/3/howto/descriptor.html#properties:

class Constant(object):
    def __init__(self, value)
        def _(self):
            return value
        self.fget = _

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return self.fget(obj)

This is probably simpler than subclassing property and overriding __set__ and __del__ to "unimplement" them. But, I like my idea of a wrapper around a regular property better.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • Well it's read-only from outside the class but this does not mean it can be changed by the class itself ;) But I like your first attempt. Thanks! – Praind Jun 29 '18 at 15:04