Skip to content Skip to sidebar Skip to footer

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 rea

Solution 1:

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

classMyClass(object):

    def__init__(self):
        self._conn = None    @propertydefconn(self):
        if self._conn isNone:
            self._conn = ConnectToDatabase()
        return self._conn

    defdo_something1(self):
        self.conn.do_something1()

    defdo_something2(self):
        self.conn.do_something2()

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

defprerequisite(prerequisite_function, *pre_args, **pre_kwargs):
    defwrapper(func):
        defwrapped(self, *args, **kwargs):
            prerequisite_function(self, *pre_args, **pre_kwargs)
            return func(self, *args, **kwargs)
        return wrapped
    return wrapper

 classMyClass(object):

     def__init__(self):
         self.conn = Nonedefconnect(self):
         if self.conn isNone:
             self.conn = ConnectToDatabase()

     @prerequisite(connect)defdo_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.

Solution 2:

I do like sr2222's approach of using a property for getting the connection, however here is an approach with decorators which may be useful or at least informative (use of functools.wraps() is optional):

import functools

defrequire_connection(f):
    @functools.wraps(f)defwrapped(self, *args, **kwargs):
        self.connect()
        return f(self, *args, **kwargs)
    return wrapped

classMyClass(object):
    def__init__(self):
        self.conn = Nonedefconnect(self):
        if self.conn : return
        self.conn = ConnectToDatabase()

    @require_connectiondefdo_something1(self):
        self.conn.do_something1()

    @require_connectiondefdo_something2(self):
        self.conn.do_something2()

Solution 3:

Similar to sr2222's solution, but calling it what it is: a cached_property.

The code is more compact, uses reusable building blocks, and in my opinion more readable.

classMyClass(object):@cached_propertydefconn(self):
        return ConnectToDatabase()

    defdo_something1(self):
        self.conn.do_something1()

    defdo_something2(self):
        self.conn.do_something2()

The definition of cached_property is found here.

Post a Comment for "Use A Class Decorator To Implement Late-initialization"