parent-child object design question
Steven D'Aprano
steve at REMOVE.THIS.cybersource.com.au
Sun Feb 4 11:31:20 EST 2007
On Fri, 02 Feb 2007 13:53:21 -0800, manstey wrote:
> Hi,
>
> There was a mistake above, and then I'll explain what we're doing:
>>>> insCacheClass = CacheClass(oref)
>>>> insCacheProperty = CacheProperty(insOref,'Chapter')
>
> should have been
>>>> insCacheClass = CacheClass(oref)
>>>> insCacheProperty = CacheProperty(insCacheClass ,'Chapter')
>
> Now, to answer some questions.
> 1. Cache refers to Intersystems Cache database, an powerful oo dbase
> that holds our data.
> 2. It comes with a pythonbinding, but unfortunatley the API, written
> in C as a python extension, only provides old-style classes, which is
> why we wrap the oref (an in-memory instance of a Cache class/table)
> with CacheClass. This allows us to add attributes and methods to the
> CacheClass, the most important being CacheProperty, which is a class
> corresponding to the Cache property/field classes of the dbase.
You can add attributes and methods to old-style classes.
> 3. The pythonbind also has a strange behaviour, to our view. It gets
> and sets values of its properties (which are classes),
Are you sure you're using the word "classes" correctly? That seems ...
strange. I'm wondering whether the properties are class _instances_.
> via the
> 'parent' oref, i.e. oref.set('Name','Peter'). But we want a pythonic
> way to interact with Cache, such as, insCacheClass.Name='Peter'. and
> insOref.Name.Set().
Okay, let me see that I understand what happens. Here's some pseudo-code
of what I think you are currently doing:
oref = get_a_reference_to_Cache_database() # or whatever
# now do work on it using the python bindings.
oref.set("Name", "Peter")
oref.set("Something", "Else")
Here's a wrapper for the bindings, so they work more pythonically:
class Oref_Wrapper(object):
def __init__(self, oref):
self._oref = oref # save the oref for later use
# Delegate attribute access to the oref
def __setattr__(self, name, value):
return self._oref.set(name, value)
def __getattr__(self, name):
return self._oref.get(name) # or whatever the oref does
def __delattr__(self, name):
return self._oref.del(name) # or whatever the oref does
This is how you use it:
oref = get_a_reference_to_Cache_database() # or whatever
# re-bind the name to a wrapped version
oref = Oref_Wrapper(oref)
# now do work on it
oref.Name = "Peter"
oref.Something = "Else"
> The code above (in post 7) does this, but as I
> asked, by storing the parent instance (insCacheClass) inside each of
> its attributes (insCacheProperty1,2, etc).
Do you use insCacheClass and insCacheProperty for anything other than
making the bindings more Pythonic? Because for the life of me I can't work
out what they're supposed to do!
> 4. Another reason we want a new-style class wrapped around the oref,
> is that each oref has many methods on the server-side Cache database,
> but they are all called the same way, namely,
> oref.run_obj_method('%METHODNAME',[lisArgs]). We want to call these in
> python in the much better insCacheClass.METHODNAME(Args). E.g. we
> prefer insCacheClass.Save() to oref.run_obj_method('%Save',[None]).
Using my code above, oref.METHODNAME(args) would resolve to:
oref._oref.get("METHODNAME")(args)
which may not do what you want.
If you know all the possible METHODNAMES, then that's easy enough to fix:
create methods at runtime. (If you don't know the methods, the problem
becomes too hard for me to work out at 3am, but will probably still be
solvable.)
Change the __init__ method above to something like this (untested):
import new
class Oref_Wrapper(object):
def __init__(self, oref):
self._oref = oref # save the oref for later use
METHODNAMES = ["Save", "Clear", "Something"]
for name in METHODNAMES:
function = lambda self, *args: \
self._oref.run_obj_method("%"+name, args)
method = new.instancemethod(function, name)
self.__dict__[name] = method
then define the __getattr__ etc. methods as before, and (hopefully!) you
are done:
oref.Save()
oref.Clear(1, 2, 3, 7)
I hope this was of some help.
--
Steven.
More information about the Python-list
mailing list