-1

I have a class in python with lot of methods as follows:

import logging
logger = logging.getLogger(__name__)

class BaseWorkFlow:
   def __init__(self, response=None):
       self.response = response

   def func1(self):
       self.response = 10
       logger.info(self.response.data)

   def func2(self):
       self.response = 20
       logger.info(self.response.data)

   def func3(self):
       self.response = 20
       logger.info(self.response.data)

As is evident, every time the value of self.response changes, I need to log it. Currently i am using explicit logging statements to do this.However, now my code is littered with log statements.Also it is very difficult to update log statements manually when new methods are added.

Is there any way of writing a function or a decorator that automatically does the logging operation anytime self.response is assigned a new value in any of the class methods ?

Amistad
  • 7,100
  • 13
  • 48
  • 75
  • 2
    Possible duplicate of [How to trigger function on value change?](https://stackoverflow.com/questions/6190468/how-to-trigger-function-on-value-change) – metatoaster Feb 22 '19 at 06:32

3 Answers3

2

One possible approach is to use property (properties are implemented with descriptors in Python so you may write your own descriptor to get more powerful and flexible attribute access control):

class BaseWorkFlow:

    def __init__(self, response=None):
        self._response = response

    @property
    def response(self):
        return self._response

    @response.setter
    def response(self, value):
        self._response = value
        # logging after setting
        print(f'self._response = {self._response}')

    def func1(self):
        self.response = 10

    def func2(self):
        self.response = 20

    def func3(self):
        self.response = 20

bwf = BaseWorkFlow()
bwf.func1()
bwf.response = 101

Output:

self._response = 10
self._response = 101
0

You can achieve it by separating your code on updating the response value and logging.

import logging
logger = logging.getLogger(__name__)

class BaseWorkFlow:

    def __init__(self, response=None):
        self.response = response

    def func1(self):
        self.update_response(10)

    def func2(self):
        self.update_response(20)

    def func3(self):
        self.update_response(20)

    def update_response(response_value):
        self.response = response_value
        logger.info(selfl.response.data)
bumblebee
  • 1,811
  • 12
  • 19
0

Use __setattr__ to catch changing value of class attribute.

import logging
logger = logging.getLogger(__name__)

class BaseWorkFlow:
    def __init__(self, response=None):
        self.response = response

    def __setattr__(self, name, value):
        if name == 'response':
            logger.info('{} is set to {}'.format(name, value))

    def func1(self):
        self.response = 10

    def func2(self):
        self.response = 20

    def func3(self):
        self.response = 30
Ellisein
  • 878
  • 6
  • 17
  • this is nice..the only issue is that the first time the class is instantiated, the init method gets fired and i get something like" response is set to None" in my logs..is there any way to avoid this.. – Amistad Feb 22 '19 at 09:15
  • @Amistad `__setattr__` method is called when any value is set. So if you initialize `BaseWorkFlow` class with `response=None`, `__setattr__` is also called. It is unavoidable. – Ellisein Feb 25 '19 at 01:12