Search code examples
pythonpython-decoratorspython-class

How to transfer an immutable part of a function to other projects


In the print_foo function, there is a part of the code that changes from project to project. And there is a part of the code which is always the same. It is responsible for working with the Counter class.

What's the best way to change the code to just move the unchanged part of the function from project to project?

Is it possible to implement this through the decorator? If so, how can the decorator query the attributes of an object, in this case foobar. And how would it save them to an object of the Counter class?

class Counter(object):
    def __init__(self):
        self.foo = 0
        self.status = 'Off'

    def counter_foo(self, n):
        self.foo += n

    def set_status(self, status):
        self.status = status


class First(object):
    def __init__(self):
        self.counter = Counter()
        self.status = 'On'

    def print_foo(self, n=1):
        # This part is changing in every project
        print('foo' * n)

        # This part doesn't change. And this part I want take out separately
        self.counter.counter_foo(n)
        if self.status == 'On':
            self.counter.set_status(self.status)


def main():
    foobar = First()
    foobar.print_foo(8)

I want in the First, just write the function

def print_foo(self, n=1):
        print('foo' * n)

But with the preservation of the functionality of this part

self.counter.counter_foo(n)
        if self.status == 'On':
            self.counter.set_status(self.status)

In a real project, it is 6 functions and tens of lines. I can't copy them every time by hand.


Solution

  • You could declare a decorator as follows and still use it for your scope since the self name is just a name at the end...

    from functools import wraps
    
    def increment_counter(func):
        @wraps(func)
        def wrapper_func(self, *args, **kwargs):
            result = func(self, *args, **kwargs)
            self.counter.counter_foo(n)
            if self.status == 'On':
               self.counter.set_status(self.status)
            return result
        return wrapper_func    
    

    You can then decorate print_foo with it as:

    class First:
      @increment_counter
      def print_foo(self, n=1):
        # This part is changing in every project
        print('foo' * n)