Multiple instances and wrong parental links

J

Josh English

I have hit yet another wall. I am dynamically creating a class and then creating instances of that class. The class relies on a second class to store a list of objects. (This is simplified from the the original by a factor of about 20. The real program is trying to create a Python object around an XML definition object.)

Here's the code:

## OPTION ONE for class: ElementList
### Not really a list, but a wrapper that behaves like a list
class ElementList(object):
def __init__(self, parent, name):
self._parent = parent
self._name = name

def MakeWrapper(checker, _addNameAsAttribute = False ):

## OPTION TWO for class: ElementList
class Wrap(object):

## OPTION THREE for class: Elementlist

def __init__(self, name):
self._name = name
setattr(Wrap, 'stuff', ElementList(self, 'test'))

Wrap.__name__= checker.title()

return Wrap

if __name__ == '__main__':

Dude = MakeWrapper('Dude')
print Dude
d1 = Dude('Josh')
print d1, d1.stuff

# creating the second instance changes the behavior of the subclass
d2 = Dude('Ben')
print d2, d2.stuff
print d1.stuff._parent
print d2.stuff._parent

#creating a third instance changes the behavior of all the subclasses
d3 = Dude('David')
print d3, d3.stuff
print d1.stuff._parent, d2.stuff._parent, d3.stuff._parent

## END CODE

And here is the output:
<class '__main__.Dude'>
<__main__.Dude object at 0x00DFB930> <__main__.ElementList object at 0x00DFB950>
<__main__.Dude object at 0x00DFB730> <__main__.ElementList object at 0x00DFB770>
<__main__.Dude object at 0x00DFB730>
<__main__.Dude object at 0x00DFB730>
<__main__.Dude object at 0x00DFB870> <__main__.ElementList object at 0x00DFB9B0>
<__main__.Dude object at 0x00DFB870> <__main__.Dude object at 0x00DFB870> <__main__.Dude object at 0x00DFB870>

The 'stuff' attribute is an ElementList object linked back to the parent instance, but every time I create an instance, every instance's 'stuff' links back to the last instance created.

I'm not sure why this is happening, or how to prevent it.

Any suggestions?
 
C

ChasBrown

I have hit yet another wall. I am dynamically creating a class and then creating instances of that class. The class relies on a second class to store a list of objects. (This is simplified from the the original by a factor of about 20. The real program is trying to create a Python object around an XML definition object.)

Here's the code:

## OPTION ONE for class: ElementList
### Not really a list, but a wrapper that behaves like a list
class ElementList(object):
def __init__(self, parent, name):
self._parent = parent
self._name = name

def MakeWrapper(checker, _addNameAsAttribute = False ):

## OPTION TWO for class: ElementList
class Wrap(object):

## OPTION THREE for class: Elementlist

def __init__(self, name):
self._name = name
setattr(Wrap, 'stuff', ElementList(self, 'test'))

Wrap.__name__= checker.title()

return Wrap

if __name__ == '__main__':

Dude = MakeWrapper('Dude')
print Dude
d1 = Dude('Josh')
print d1, d1.stuff

# creating the second instance changes the behavior of the subclass
d2 = Dude('Ben')
print d2, d2.stuff
print d1.stuff._parent
print d2.stuff._parent

#creating a third instance changes the behavior of all the subclasses
d3 = Dude('David')
print d3, d3.stuff
print d1.stuff._parent, d2.stuff._parent, d3.stuff._parent

## END CODE

And here is the output:



<class '__main__.Dude'>
<__main__.Dude object at 0x00DFB930> <__main__.ElementList object at 0x00DFB950>
<__main__.Dude object at 0x00DFB730> <__main__.ElementList object at 0x00DFB770>
<__main__.Dude object at 0x00DFB730>
<__main__.Dude object at 0x00DFB730>
<__main__.Dude object at 0x00DFB870> <__main__.ElementList object at 0x00DFB9B0>
<__main__.Dude object at 0x00DFB870> <__main__.Dude object at 0x00DFB870> <__main__.Dude object at 0x00DFB870>

The 'stuff' attribute is an ElementList object linked back to the parent instance, but every time I create an instance, every instance's 'stuff' links back to the last instance created.

If every instance's <whatever> is the same, one guesses that the
I'm not sure why this is happening, or how to prevent it.

It's perfectly predictable; to understand what is happening, compare:
class Bar(object):
def __init__(self):
setattr(Bar, 'stuff', {})
return Bar
Dude = foo()
a = Dude()
b = Dude()
a.stuff['foo'] = 2
b.stuff {'foo': 2}
c = Dude()
a.stuff
{}

with the behavior (which I think you expected) of:
class Bar(object):
def __init__(self):
setattr(self, 'stuff', {})
return Bar
Dude = foo()
a = Dude()
b = Dude()
a.stuff['foo'] = 2
b.stuff {}
c = Dude()
a.stuff
{'foo': 2}

Cheers - Chas
 
J

John Nagle

setattr(Wrap, 'stuff', ElementList(self, 'test'))

Right. As the previous poster wrote, that line is the
basic problem.

It's not entirely clear what you're trying to do, but it
seems to be overly complex. You could have Wrap inherit
from ElementList, if you want each Wrap class to be a
subclsss of ElementList. Or simply have a line in the __init__
of Wrap like

self.something = ElementList(self, whatever)

John Nagle
 
S

Steven D'Aprano

I have hit yet another wall. I am dynamically creating a class and then
creating instances of that class. The class relies on a second class to
store a list of objects. (This is simplified from the the original by a
factor of about 20.

Sounds like it's about 40 times too complex then: aim for something about
half the complexity of this "simplified" version.

The real program is trying to create a Python object
around an XML definition object.)

Here's the code:

## OPTION ONE for class: ElementList
### Not really a list, but a wrapper that behaves like a list class
ElementList(object):
def __init__(self, parent, name):
self._parent = parent
self._name = name


Doesn't behave much like a list for me :)

def MakeWrapper(checker, _addNameAsAttribute = False ):
## OPTION TWO for class: ElementList
class Wrap(object):
## OPTION THREE for class: Elementlist
def __init__(self, name):
self._name = name
setattr(Wrap, 'stuff', ElementList(self, 'test'))
Wrap.__name__= checker.title()
return Wrap


Your problem is that all the instances from a MakeWrapper class share the
same "stuff" attribute, which is attached to the class Wrap. What you
probably want is:

setattr(self, 'stuff', ElementList(self, 'test'))

instead. What you *need* is to rethink this complicated strategy for a
simpler one.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top