A question on decorators

Tim Henderson tim.tadh at gmail.com
Wed Mar 26 15:10:29 EDT 2008


Hello

I am writing an application that has a mysql back end and I have this
idea to simplify my life when accessing the database. The idea is to
wrap the all the functions dealing with a particular row in a
particular in a particular table inside a class. So if you have a
table that looks like this:

id   str1       str2        pickled_data1   pickled_data2
0    woeif      aposf       (bin)                  (bin)
1    ofime      powe        (bin)                  (bin)
...
n    oiew       opiwe       (bin)                  (bin)

you can access this table like this

t = Table(id) #to load a pre-entered row
t2 = Table(id, str1, str2, data1, data2) #to create a new row

when you change a an attribute of the class like this...
t.str1 = 'new value'

it automatically updates the database backend.

I have what I just described working. However I want an easier way to
deal with my pickled_data. Right now I am pickling dictionaries and
list types. Now there is one problem with this, let me demonstrate

t.data.update({'new key':'new value'})
print t.data
{... 'new key':'new value' ...}

which makes it appear that the database has been updated as well, but
in fact it hasn't to update the database with this scheme you actually
have to do this.

t.data.update({'new key':'new value'})
t.data = t.data

this is not ideal so I subclassed the built in dict type like this:

class _my_dict(dict):

    def __init__(self, row_index_name, row_index, column_name, a=None,
**kwargs):
        self.row_index_name = row_index_name
        self.row_index = row_index
        self.column_name = column_name
        self.write_access = True
        if (a == None): dict.__init__(self, kwargs)
        else: dict.__init__(self, a)

        self.update_db()

    def __delitem__(self, key):
        if self.write_access:
            dict.__delitem__(self, key)
            self.update_db()

    def __setitem__(self, key, value):
        if self.write_access:
            dict.__setitem__(self, key, value)
            self.update_db()


    def clear(self):
        if self.write_access:
            dict.clear(self)
            self.update_db()

    ...
    more methods which are simliar
    ...

    def update_db(self):
        if self.write_access:
            con = get_dbConnection()
            cur = con.cursor()

            table = self.experiment.TABLE
            row_index_name = self.row_index_name
            row_index = self.row_index
            column_name = self.column_name
            column_value = MySQLdb.escape_string(pickle.dumps(self))

            q1 = '''UPDATE %(table)s
            SET %(column_name)s = '%(column_value)s'
            WHERE %(row_index_name)s = '%(row_index)s'  ''' % locals()

            cur.execute(q1)
            con.close()


Now while this works, it is a lot of work. What I want to be able to
do is something where I write one decorator function that
automatically updates the database for me. So let us pretend I have
this function.

let: dec_update_db() be my decorator which updates the dictionary.

to use this function it seems I would probably still have to subclass
dict like this:

class _my_dict2(dict):

    @dec_update_db
    def __init__(self, row_index_name, row_index, column_name, a=None,
**kwargs):
        self.row_index_name = row_index_name
        self.row_index = row_index
        self.column_name = column_name
        self.write_access = True
        if (a == None): dict.__init__(self, kwargs)
        else: dict.__init__(self, a)

    @dec_update_db
    def __delitem__(self, key):
        dict.__delitem__(self, key)

    @dec_update_db
    def __setitem__(self, key, value):
        dict.__setitem__(self, key, value)

    @dec_update_db
    def clear(self):
        dict.clear(self)

    ... and so on ...

this is also not ideal. because I still have to apply the decorator to
every function which changes the dictionary.

What I really want is a way to have the decorator applied
automatically every time a method in dict or a sub class is called. I
feel like this must be possible. Has any one here done anything like
this before?

Thank you for reading my long post, I hope you understand what I am
asking especially since the code in it is not very good.

cheers
Tim Henderson



More information about the Python-list mailing list