[Zope] Another import doesn't find the module

Dylan Reinhardt zope@dylanreinhardt.com
28 May 2003 20:38:28 -0700


On Wed, 2003-05-28 at 18:13, Stacy Roberts Ladnier wrote:
> >>Why not create a single
> >>product that can instantiate itself (or subobjects) more than one way?
> 
> The product I am creating is more like an application. 

Excellent.

> It has container 
> objects at the top, 

Cool.

> and several subfolders 

OK.

> that contain hundreds of 
> objects 

Yeah.

> that make up a 'record'. 

Hundreds of objects == one "record"?  Hmmm...

> I guess you can say I have tons of 
> data models to go in this application. 

That's not typically a hallmark of good design or an easily-supported
system, but I'm not the one with the requirements in front of me.

> 
> My whole problem is trying to get things to instantiate more than one 
> way. 

Ah... well, in that case I have a couple cool tricks to share.

> Once a user has created a record of type #1, he must have the 
> ability to go back and add an extension of type A. 

So... this is a "record" in the same sense as above where a record is
defined by hundreds of ZMI objects?  Does the "extension" consist of an
additional object added through the ZMI?  Or do you just want your type
#1 object to have a new interface?

>  I can't force the user to 
> create a record of tye #1 with the type A extension up front.

Why not?  Anything a user can do, Zope can do for them.

>  If only 
> it were that easy, I wouldn't be having such a pain.

Often when things are difficult in Zope (and open source in general), it
is because one is unaware that someone else already solved the problem.

Leaving that aside, there's a couple different ways you could attack the
problem of returning different types of instances

If you want the decision made at instantiation time, you can do that in
your constructor method:

--------

manage_addMyThing(self, id, REQUEST=None):
    if some_test:
        self._setObject(id, Class1(id))
    else:
        self._setObject(id, Class2(id))

class Class1:
    def __init__(self, id):
        self.id = id

    meta_type = 'MyThing'


class Class2:
    def __init__(self, id):
        self.id = id

    meta_type = 'MyThing'

--------

You'll want to ensure that both classes either have the same interface
(recommended) or at least have an intelligent way of failing when a
given interface isn't found.  Having them both inherit from a base class
is an approach well worth considering.

If you want to be able to change classes on the fly, that's a bit
trickier, but not by much.

------

class One:
    def __init__(self, name):
        self.name = name

    def whoami(self):
        return self.name
       

class Two:
    def __init__(self, name):
        self.name = name

    def whoami(self):
        return "I am %s, a class Two object." % self.name

def SwitchClass(object, target_class):
        if target_class == 'One':
            new_obj = One(object.name)
        if target_class == 'Two':
            new_obj = Two(object.name)
        new_obj.__dict__ = object.__dict__
        return new_obj

-------

If you entered these classes into an interactive prompt, you can then
see how easily you can change back and forth:

>>> a = One('my thing')
>>> a.foo = 'this is the foo attribute'
>>> a.whoami()
'my thing'
>>> a = SwitchClass(a, 'Two')
>>> a.whoami()
'I am my thing, a class Two object.'
>>> a.foo
'this is the foo attribute'
>>> 

The execution in a Python product may be a bit more sophisticated, but
the general idea is the same.  Python makes it pretty easy to change
stuff on the fly and makes it easy to use objects polymorphically so
that what type your object is often doesn't matter very much.

Hope that helps and if you want to hash out some possible alternatives
to your data model, let us know.

Dylan