Re: A lazy-committing database object with curry?
From: Jp Calderone (exarkun_at_intarweb.us)
Date: 01/19/04
- Next message: Peter Otten: "Re: Delayed evaluation and setdefault()"
- Previous message: Erik Max Francis: "Re: HowTo distinguish between File and Directory"
- In reply to: Tim Lesher: "A lazy-committing database object with curry?"
- Next in thread: Tim Lesher: "Re: A lazy-committing database object with curry?"
- Reply: Tim Lesher: "Re: A lazy-committing database object with curry?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Mon, 19 Jan 2004 14:05:08 -0500 To: python-list@python.org
On Mon, Jan 19, 2004 at 08:45:45AM -0800, Tim Lesher wrote:
> I'm writing a database helper class that represents records in a SQL
> database as objects. I want to be able to instantiate the objects
> (from the database), play with their values locally, then lazily
> commit the changes all at once (via an explicit commit call). Other
> than the call to Commit(), I don't want clients of this class to have
> to think about the fact that there's a database behind it all--there are
> some interesting and non-obvious dependencies on the particular values
> that are committed together, and I want to hide that in the Commit() call.
Sounds familiar...
>
> I'm going to have a number of these, so I wanted to come up with a
> solution that's short on glue code and can easily be aggregated into
> all the classes that represent record types. This is what I've come
> up with:
>
> # Simple currying class, no kwargs
> class curry:
> def __init__(self, fun, *args):
> self.fun = fun
> self.pending = args[:]
> def __call__(self, *args):
> return self.fun(*(self.pending + args))
>
You don't need to copy args, Python has done that for you already.
>
> # Simple table: two columns, "title" and "description"
> class SomeRecordType(object):
> def __init__(self, title, description):
> self.__modifications = {}
>
> # Avoid triggering propset on init
> self.__dict__['title'] = title
> self.__dict__['description'] = description
>
Are you sure? How will the initial values be committed to the database,
if you don't catch them in the modifications dict? I guess you might be
handling initial values somewhere else, in code you didn't post...
> def __getValue(name, self):
> try:
> return self.__modifications[name]
> except KeyError:
> return self.__dict__[name]
>
> def __setValue(name, self, newValue):
> self.modifications[name] = newValue
>
> name = property(curry(__getValue, 'title'),
> curry(__setValue, 'title'))
> description = property(curry(__getValue, 'description'),
> curry(__setValue, 'description'))
Nift. You surely don't use the full capabilities of currying here, but
you are incurring a double function call overhead on every setattr now.
Here's another way to do it:
def makeModificationFunctions(name):
def modget(self, value):
try:
return self.__modifications[name]
except KeyError:
return self.__dict__[name]
def modset(self, value):
self.__modifications[name] = value
return modget, modset
title = property(*makeModificationFunctions('title'))
description = property(*makeModificationFunctions('description'))
Of course, you can go one step better and use a metaclass:
class MetaRecordType(type):
def __new__(metaclass, name, bases, ns):
for k, v in ns.items():
if v is makeModificationFunctions
ns[k] = property(*v(k))
return type.__new__(metaclass, name, bases, ns)
and now in the class definition simply say:
__metaclass__ = MetaRecordType
title = makeModificationFunctions
description = makeModificationFunctions
>
> def Commit(self):
> if self.modifications != {}:
This can be just "if self.__modifications:"
> # - snip - Do database commit and clear modifications
> self.__dict__.update(self.modifications)
> self.modifications = {}
>
> So I can do this:
>
> foo = myDb.LookupTitleRecord('some title')
> print foo.description # 'foo'
> foo.description = 'bar' # not updated in the DB yet
> print foo.description # 'bar'
> foo.Commit() # now updated in the DB
>
>
> Are there any pitfalls to doing this? Am I being dazzled by the shiny
> new toy that is currying? Is there another simple solution, or a
> refinement of this one, that I'm not seeing?
>
One possible problem is failed commits. If you're doing commits
transactionally, and the transaction fails, your in memory objects will
retain their now-inconsistent values while the database remains unupdated.
If you're not using transactions.. well that's a whole other problem :)
You may want to look at xsdb and atop. Neither uses SQL, but both have
developed pretty heavily on some of the ideas you're tinkering around with.
Jp
- Next message: Peter Otten: "Re: Delayed evaluation and setdefault()"
- Previous message: Erik Max Francis: "Re: HowTo distinguish between File and Directory"
- In reply to: Tim Lesher: "A lazy-committing database object with curry?"
- Next in thread: Tim Lesher: "Re: A lazy-committing database object with curry?"
- Reply: Tim Lesher: "Re: A lazy-committing database object with curry?"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|