Search code examples
pythonpython-3.xclassdecoratorpython-decorators

How to execute a Class method from decorator function


I have a class with a main dictionary self.wardrobe, which is being saved to a JSON file by the method: self.save().

I am now trying to make a decorator which calls the self.save(), method after executing the decorated method.

Thanks in advance :)

Edit:

This is a try defining the decorator outside of the class (I also tried @staticmethod but it didn't work somehow):

def decorate_save(func):
    def inner(*args, **kwargs):
        val = func(*args, **kwargs)
        self.save()
        return val
    return inner()

Second Edit:

this is the part of the class important for this problem:

class Wardrobe:
    def __init__(self, filepath):
        self.filepath = filepath
        with open(self.filepath, 'r') as f:
            self.wardrobe = json.load(f)
        # self.wardobe is a dict

    def duplicate(self, index: int):
        item = self.wardrobe['all'][index]
        self.wardrobe['all'].append(item) # self.wardrobe['all'] is a list

    def save(self):
        with open(self.filepath, 'w') as f:
            json.dump(self.wardrobe, f, indent=4)

Summary: I want to create a decorator for the method duplicate(), which executes the method save() right after.

(of course I have other functions than duplicate(), which need to save afterwards too. thats why I dont just call save() in the method.)


Solution

  • When decorating a method self is the first argument passed to inner. You could do something like:

    import json
    
    def decorate_save(method):
        def inner(self, *args, **kwargs):
            val = method(self, *args, **kwargs)
            self.save()
            return val
        return inner
    
    class Wardrobe:
        def __init__(self, filepath):
            self.filepath = filepath
            with open(self.filepath, 'r') as f:
                self.wardrobe = json.load(f)
            # self.wardobe is a dict
    
        @decorate_save
        def duplicate(self, index: int):
            item = self.wardrobe['all'][index]
            self.wardrobe['all'].append(item) # self.wardrobe['all'] is a list
    
        def save(self):
            with open(self.filepath, 'w') as f:
                json.dump(self.wardrobe, f, indent=4)
    
    w = Wardrobe('input_nogit.json')
    w.duplicate(1)
    

    Input json:

    {
        "all": [
            "socks",
            "sandals"
        ]
    }
    

    Output json:

    {
        "all": [
            "socks",
            "sandals",
            "sandals"
        ]
    }