I would like to define a metaclass that will allow me to create properties (i.e. setter, getter) in a new class based on the attributes of the class.
For example, I would like to define a class:
class Person(metaclass=MetaReadOnly): name = "Ketty" age = 22 def __str__(self): return ("Name: " + str(self.name) + "; age: " + str(self.age))
But I would like to get something like this:
class Person(): __name = "Ketty" __age = 22 @property def name(self): return self.__name; @name.setter def name(self, value): raise RuntimeError("Read only") @property def age(self): return self.__age @age.setter def age(self, value): raise RuntimeError("Read only") def __str__(self): return ("Name: " + str(self.name) + "; age: " + str(self.age))
Here is the metaclass I wrote:
class MetaReadOnly(type): def __new__(cls, clsname, bases, dct): result_dct = {} for key, value in dct.items(): if not key.startswith("__"): result_dct["__" + key] = value fget = lambda self: getattr(self, "__%s" % key) fset = lambda self, value: setattr(self, "__" + key, value) result_dct[key] = property(fget, fset) else: result_dct[key] = value inst = super(MetaReadOnly, cls).__new__(cls, clsname, bases, result_dct) return inst def raiseerror(self, attribute): raise RuntimeError("%s is read only." % attribute)
However, it does not work properly.
client = Person() print(client)
Sometimes I get:
Name: Ketty; age: Ketty
sometimes:
Name: 22; age: 22
or even an error:
Traceback (most recent call last): File "F:\Projects\TestP\src\main.py", line 38, in <module> print(client) File "F:\Projects\TestP\src\main.py", line 34, in __str__ return ("Name: " + str(self.name) + "; age: " + str(self.age)) File "F:\Projects\TestP\src\main.py", line 13, in <lambda> fget = lambda self: getattr(self, "__%s" % key) AttributeError: 'Person' object has no attribute '____qualname__'
I found an example of how this can be done in a different way ( Python classes: dynamic properties ), but I would like to do it using a metaclass, do you know how this can be done, or is this possible at all?