A question on decorators

Diez B. Roggisch deets at nospam.web.de
Wed Mar 26 21:23:40 CET 2008


Tim Henderson schrieb:
> 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?

There are a few possibilities - one of them is using a metaclass to 
apply the decorator to alle methods.

Diez



More information about the Python-list mailing list