0

I'm trying to make value inside a class non-changeable, while making it accessible with the class name.

Here's my code snippet:

class readonly:
    def __init__(self, val):
        self.val = val

    def __get__(self, instance, owner):
        return self.val(owner) 
       
    def __set__(self, instance, value):
        raise AttributeError("Value can't be changed")
    
class A:
    @readonly
    def abc(value):
        return 5

Result and Problem

In [1]: A().abc
Out[1]: 5

In [2]: A.abc
Out[2]: 5

In [3]: A().abc = 2
Traceback (most recent call last):

  File "<ipython-input-105-ba63e690d374>", line 1, in <module>
    A().abc = 2

  File "<ipython-input-101-24787a3d51ab>", line 9, in __set__
    raise AttributeError("Value can't be changed")

AttributeError: Value can't be changed


In [4]: A.abc = 2

In [5]: A().abc
Out[5]: 2

Here, A().abc is restricting changes made to abc, but A.abc fails.


What I expect

Both A().abc and A.abc should restrict any changes made to abc


Awaiting valuable reply

Thanks!

Preetkaran

Python Ver: 3.7.7

Preetkaran Singh
  • 502
  • 5
  • 19
  • Does this answer your question? [Using property() on classmethods](https://stackoverflow.com/questions/128573/using-property-on-classmethods), also [How to create a read-only class property in Python?](https://stackoverflow.com/questions/3203286/how-to-create-a-read-only-class-property-in-python) – metatoaster Jul 05 '20 at 13:29
  • 1
    You can't prevent assignments to `A.abc` without a custom metaclass. I wouldn't worry about that case. You can't make anything truly read-only in pure Python; you can only make it hard to accidentally overwrite a value, unless you implement something as a C extension. – chepner Jul 05 '20 at 13:34
  • Really, all you need here is `abc = property(lambda v: 5)`. The lack of a setter will make assignments to `A().abc` fail with the desired `AttributeError`. – chepner Jul 05 '20 at 13:36
  • Thanks @chepner for a one-line expression for partial solution of the problem! If I'd stick to the question, then any tips/links on how to get it truly read-only, it would be a great help. – Preetkaran Singh Jul 05 '20 at 13:53

1 Answers1

0

As suggested by @chepner and after a lot of research, I found a possible solution to the problem using custom metaclass.

class readonly(type): # type is the parent class, extended it to 'readonly' class
    abc = 5
    
    def __setattr__(self, name, value):
        raise Exception("Value can't be changed")

        
class A(metaclass=readonly):
     def __setattr__(self, name, value):
         raise Exception("Value can't be changed")

# Console
A.abc                 # 5
A.abc = 2             # 'Value can't be changed'
Preetkaran Singh
  • 502
  • 5
  • 19