Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use a class decorator to implement late-initialization

I am using some classes which need to connect to databases. The connection is only really needed when performing a real action. I want to delay the connection phase until it is really needed. For that, I want to do something similar to this:

class MyClass

    def __init__(self):
        self.conn = None

    def connect(self):
        if self.conn : return
        self.conn = ConnectToDatabase()

    @connect
    def do_something1(self):
        self.conn.do_something1()

    @connect
    def do_something2(self):
        self.conn.do_something2()

But I do not know how to define the connect decorator for the class.

I could of course do something like this:

    def do_something1(self):
        self.connect()
        self.conn.do_something1()

But using decorators seems a more readable solution. Is it possible?

like image 429
blueFast Avatar asked Dec 27 '22 07:12

blueFast


1 Answers

Rather than trying to decorate the functions that require connections, use a property for getting the connection itself.

class MyClass(object):

    def __init__(self):
        self._conn = None

    @property
    def conn(self):
        if self._conn is None:
            self._conn = ConnectToDatabase()
        return self._conn

    def do_something1(self):
        self.conn.do_something1()

    def do_something2(self):
        self.conn.do_something2()

As for a straight decorator example, playing off F.J's answer:

def prerequisite(prerequisite_function, *pre_args, **pre_kwargs):
    def wrapper(func):
        def wrapped(self, *args, **kwargs):
            prerequisite_function(self, *pre_args, **pre_kwargs)
            return func(self, *args, **kwargs)
        return wrapped
    return wrapper

 class MyClass(object):

     def __init__(self):
         self.conn = None

     def connect(self):
         if self.conn is None:
             self.conn = ConnectToDatabase()

     @prerequisite(connect)
     def do_something(self):
         self.conn.do_something()

You could also make prerequisite more robust by making it create descriptors so that it can behave correctly for functions and static methods as well as class and instance methods.

like image 197
Silas Ray Avatar answered Jan 15 '23 06:01

Silas Ray