Search code examples
pythonpython-3.xpython-decorators

Conditionals decoration of functions in Python


For debugging purpose I want to write a function to do this:

  1. If debug_mode == 0 doesn't echo any message.
  2. If debug_mode == 1 echoes the message to the stdout with print()
  3. If debug_mode == 2 echoes the message to a log file

I've thinked do that with function decorators (that I've never used before).

Actually, I want to substitute some print() that I've put in some points to show me intermediate values and while learn about function decorators.

I don't want to create a class to do that. This is my approach, but it doesn't work:

import logging

FORMAT = '%(asctime)s %(levelname)s %(message)s %(funcName)s'
logging.basicConfig(filename='example.log', level=logging.DEBUG, format=FORMAT, datefmt='%m/%d/%Y %I:%M:%S %p')

def debug(func):
    def _debug(deb=0, *args, **kwargs):
        if deb == 1:
            print(msg)
            func(*args, **kwargs)
        if deb == 2:
            logging.debug(msg)
    return _debug

@debug
def echo(msg, deb=0):
    pass

if __name__ == "__main__":
    debug_mode = 1
    echo("This is a debugging message!", debug_mode)

It will be better if I haven't to pass the param debug_mode and in the decorator function I can use the debug state directly from the __main__.


Solution

  • The problem with your code is the way you pass arguments. When you do echo("This is a debugging message!", debug_mode) you are in fact invoking def _debug(deb=0, *args, **kwargs) and all the arguments are messed up (deb becomes "This is a debugging message!" etc). On StackOverflow there is an amazing tutorial on how to use decorators.

    I'm not sure why do you need *args, **kwargs in you code. I personally believe that there is no need for any decoration in your particular case. Anyway, for educational purposes the working code with decorators may loo like:

    import logging
    
    FORMAT = '%(asctime)s %(levelname)s %(message)s %(funcName)s'
    logging.basicConfig(filename='example.log', level=logging.DEBUG, format=FORMAT, datefmt='%m/%d/%Y %I:%M:%S %p')
    
    def debug(func):
        def _debug(msg, deb=0):
            if deb == 1:
                func(msg, deb)
            if deb == 2:
                print 'Log: ' + msg + ' Level: ' + str(deb)
                logging.debug(msg)
        return _debug
    
    @debug
    def echo(msg, deb):
        print 'Echo: ' + msg + ' Level: ' + str(deb) 
    
    if __name__ == "__main__":
        echo("This is a debugging message!")
        echo("This is a debugging message!", 0)
        echo("This is a debugging message!", 1)
        echo("This is a debugging message!", 2)
    

    And the output:

    Echo: This is a debugging message! Level: 1
    Log: This is a debugging message! Level: 2