Workaround for calling `open()` in `__del__()` for a function decorator

31 views Asked by At

I am writing a function decorator to perform profiling of a function, it stores information about the function during execution and outputs the information into a log file. The implementation causing issues can be seen below.

import time
import sys

class _profile:
    def __init__(self, func, filepath):
        self.func = func
        self.filepath = filepath
        self.calls = []
    def __call__(self, *args, **kwargs):
        start = time.time()
        result = self.func(*args, **kwargs)
        self.calls.append(time.time() - start)
        return result
    def __del__(self):
        mean = sum(self.calls)/len(self.calls)
        with open(self.filepath, "a+") as out_file:
            output = f"'{self.func.__name__}' called {len(self.calls)} times, mean execution time of {mean}"
            out_file.write(output)

def profile(filepath=sys.stdout):
    def _profile_impl(func):
        return _profile(func, filepath)
    return _profile_impl

@profile("function.log")
def add(a, b):
    return a + b

def main():
    for i in range(100):
        add(i, i)

if __name__ == "__main__":
    main()

This is the same issue which was found in this question; summarised, the open() function is removed from __builtins__ before __del__ is called for objects in the global scope. However, the solution is not as simple as putting the offending object in a function scope as this is a function decorator which will need to work in the global scope. Are there any workarounds to this issue?

0

There are 0 answers