Home > other >  How to turn python method into setter with the help of metaclass?
How to turn python method into setter with the help of metaclass?

Time:12-15

I'm new to metaclasses, so I'm sorry, If my question is somehow stupid. I need to make a metaclass, that takes particular methods of a class and turns them into property methods or setters. So, if I have

class TestClass():
    def __init__(self, x: int):
        self._x = x

    def get_x(self):
        print("this is property")
        return self._x

    def set_x(self, x: int):
        print("this is setter")
        self._x = x

I want it to work like this:

class TestClass():
    def __init__(self, x: int):
        self._x = x

    @property
    def x(self):
        print("this is property")
        return self._x

    @x.setter
    def x(self, x: int):
        print("this is setter")
        self._x = x

For now I've just realized how to make it for property:

class PropertyConvert(type):
    def __new__(cls, future_class_name, future_class_parents, future_class_attr):
        new_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'):
                if name.startswith('get_'):
                    new_attr[name[4:]] = property(val)
                if name.startswith('set_'):
                    # ???
            else:
                new_attr[name] = val
        return type.__new__(cls, future_class_name, future_class_parents, new_attr)

But I can't figure out how to do it for setters.

CodePudding user response:

I highly recommend docs about descriptors, they are really nice written with many similar examples explained.

But answering your question, to make a setter work you need to use the same property function but fill second arguments.

class property(fget=None, fset=None, fdel=None, doc=None)

So code could look like that:

class PropertyConvert(type):
    def __new__(cls, future_class_name, future_class_parents, future_class_attr):
        new_attr = {}
        fget, fset, property_name = None, None, None
        for name, val in future_class_attr.items():
            if not name.startswith("__"):
                if name.startswith("get_"):
                    property_name = name[4:]
                    fget = val
                if name.startswith("set_"):
                    property_name = name[4:]
                    fset = val
            else:
                new_attr[name] = val
        if n:
            new_attr[property_name] = property(fget, fset)
        return type.__new__(cls, future_class_name, future_class_parents, new_attr)

  • Related