Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class-level read-only properties in Python

Tags:

python

People also ask

What is a read-only property in Python?

To define a readonly property, you need to create a property with only the getter. However, it is not truly read-only because you can always access the underlying attribute and change it. The read-only properties are useful in some cases such as for computed properties.

How do you make a class read-only in Python?

If you need to make a read-only attribute in Python, you can turn your attribute into a property that delegates to an attribute with almost the same name, but with an underscore prefixed before the its name to note that it's private convention.

What are class properties in Python?

Class Properties The property() method in Python provides an interface to instance attributes. It encapsulates instance attributes and provides a property, same as Java and C#. The property() method takes the get, set and delete methods as arguments and returns an object of the property class.

How do you make class attributes private in Python?

But there is a method in Python to define Private: Add “__” (double underscore ) in front of the variable and function name can hide them when accessing them from out of class. Python doesn't have real private methods, so one underline in the beginning of a method or attribute means you shouldn't access this method.


The existing solutions are a bit complex -- what about just ensuring that each class in a certain group has a unique metaclass, then setting a normal read-only property on the custom metaclass. Namely:

>>> class Meta(type):
...   def __new__(mcl, *a, **k):
...     uniquemcl = type('Uniq', (mcl,), {})
...     return type.__new__(uniquemcl, *a, **k)
... 
>>> class X: __metaclass__ = Meta
... 
>>> class Y: __metaclass__ = Meta
... 
>>> type(X).foo = property(lambda *_: 23)
>>> type(Y).foo = property(lambda *_: 45)
>>> X.foo
23
>>> Y.foo
45
>>> 

this is really much simpler, because it's based on nothing more than the fact that when you get an instance's attribute descriptors are looked up on the class (so of course when you get a class's attribute descriptors are looked on the metaclass), and making class/metaclass unique isn't terribly hard.

Oh, and of course:

>>> X.foo = 67
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

just to confirm it IS indeed read-only!


The ActiveState solution that Pynt references makes instances of ROClass have read-only attributes. Your question seems to ask if the class itself can have read-only attributes.

Here is one way, based on Raymond Hettinger's comment:

#!/usr/bin/env python
def readonly(value):
    return property(lambda self: value)

class ROType(type):
    CLASS_PROPERTY = readonly(1)

class Foo(object):
    __metaclass__=ROType

print(Foo.CLASS_PROPERTY)
# 1

Foo.CLASS_PROPERTY=2
# AttributeError: can't set attribute

The idea is this: Consider first Raymond Hettinger's solution:

class Bar(object):
    CLASS_PROPERTY = property(lambda self: 1)
bar=Bar()
bar.CLASS_PROPERTY=2

It shows a relatively simple way to give bar a read-only property.

Notice that you have to add the CLASS_PROPERTY = property(lambda self: 1) line to the definition of the class of bar, not to bar itself.

So, if you want the class Foo to have a read-only property, then the parent class of Foo has to have CLASS_PROPERTY = property(lambda self: 1) defined.

The parent class of a class is a metaclass. Hence we define ROType as the metaclass:

class ROType(type):
    CLASS_PROPERTY = readonly(1)

Then we make Foo's parent class be ROType:

class Foo(object):
    __metaclass__=ROType