Search code examples
pythonclassoopundefinedredefinition

How to redefine instance methods in Python?


I am making infrastructure for methods dbg (stands for debug_message), info (stands from info_message) as well as log (logging functionality).

The dbg, info, and log methods will be called whatever the user input, however, they will function differently based on the user input, such as whether the user wants the process to print DEBUG or be fully QUIET as well as whether the user wants to LOG.

I could achieve such functionality as long as I am not using an object to wrap the functionality (for multiplicity reasons). When I wrap it into an object and call it from an object I get AttributeError, that the object has no method.

class Feedbacker(object):
    def __init__(self, task):
        self.LOG = task.LOG
        self.LOG_DIR = task.LOG_DIR
        self.DEBUG = task.DEBUG
        self.QUIET = task.QUIET

        self.timestamp = datetime.now().strftime("%Y-%m-%d_%H%M%S")

        # Logging
        # Based on parameter input. Creates a log file and logs all info output.
        if self.LOG: # If logging parameter was provided -> Initiate logging
            Path(self.LOG_DIR).mkdir(parents=True, exist_ok=True) # Creates directory

            import logging
            logging.basicConfig(format='%(asctime)s %(message)s',\
                handlers=[logging.FileHandler(\
                f"{self.LOG_DIR}/ytr_log_{self.timestamp}.log", 'w', 'utf-8')]) # UTC-8
            logging.logThreads = 0
            logging.logProcesses = 0
            logger=logging.getLogger()
            logger.setLevel(logging.ERROR)
            def log(*args,**kwargs):
                msg = " ".join(args) # Joins all args into one string. " " seperator.
                logger.log(60, msg) # First agr is the log level.

        else: # If logging is not provided, log will still be run, but will do nothing.
            def log(*args,**kwargs):
                pass
        # Debug message handling
        if self.DEBUG:
            def dbg(*args, head = "DEBUG", **kwargs):
                info(*args, head = head, **kwargs)
        else:
            def dbg(self, *args, head = "DEBUG", **kwargs):
                log(f"[{head}]: ", *args, **kwargs)
                pass
        # Quiet execution
        if self.QUIET:
            def info(*args, head = "INFO", **kwargs):
                log(f"[{head}]: ", *args,**kwargs)
        else:
            def info(*args, head = "INFO", **kwargs):
                print(f"[{head}]: ", *args,**kwargs)
                log(f"[{head}]: ", *args,**kwargs)

# Example call, which does not work.
fb = Feedbacker(task)
fb.dbg("Test message")

How can I define dbg method based on instance variables?


Solution

  • Functions are values in python so you can arbitrarily reassign them.

    You can do something like this (simplified example):

    class Feedbacker(object):
        def __init__(self, switch):
            if switch:
                self.foo = self.bar
    
        def foo(*args):
            return "something"
    
        def bar(*args):
            return "something_different"
    
    print(Feedbacker(False).foo()) # something
    print(Feedbacker(True).foo()) # something_different