0

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?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • If you are concerned about performance then you may have to go with `if`. Even if you have a function similar to `assert` that is a no-op at runtime, the function still needs to be called and the arguments for this call have to be prepared. These two things may already introduce unnecessary overhead. The question to answer probably is whether you really need logging *inside* tight loops. – Daniel Junglas Nov 26 '19 at 08:26

1 Answers1

1

You can use Python's logging module, and then use logging.debug() to log whatever you need. At runtime, just specify the logging level to whatever level you need to show or hide the logs.

Otherwise, you could use the __debug__ global variable. Both options are explained in more detail in this SO question.

nheise
  • 311
  • 1
  • 8