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?
__del__for this, for objects alive at the time of interpreter shutdown, it isn't guaranteed to be called.