I'm building a small Python library that handles physics simulation, and I'd like to add some form of logging to it that traces what's happening. However, I want to be able to prevent the code from being called if it's not necessary - for instance, assert statements in Python may or may not be run at runtime. I'm also aware of function annotations, but from what I understand, these wrap functions, and can not be used inside a function. This is especially important as some of my traces would occur in for loops that might run hundreds of times, and adding an if statement doesn't seem like a fantastic solution, and neither does adding a dummy class, like my examples below.
def debug():
return True
class Logger():
def log(class_name, function_name, description):
pass
class ConsoleLogger(Logger):
def log(class_name, function_name, description):
print(class_name, function_name, description)
return true
def factorialLogger(logger):
a = 1
for i in range(0, 10):
a *= 1
logger.log("", "factorial", f"a: {a}")
return a
def factorialFlag(flag):
logger = ConsoleLogger()
a = 1
for i in range(0, 10):
a *= 1
if flag:
logger.log("", "factorial", f"a: {a}")
return a
def factorialAssert(logger):
a = 1
for i in range(0, 10):
a *= 1
assert logger.log("", "factorial", f"a: {a}")
if __name__ == "__main__":
# Insert dummy class
if debug():
factorialLogger(ConsoleLogger())
else:
factorial(Logger())
# Pass boolean flag
factorialFlag(debug())
# Use assert optimization:
factorialAssert(ConsoleLogger())
The issue with this is that I would call Logger repeatedly in the for loop, which is undesirable for performance - I'd like to instead behavior like compiling C - you can use #ifdef define a macro that is only used when compiled with a specific flag. Is there a better way to get this behaviour in Python without using an assert, which feels hacky?