Accessing container's methods
Peter Otten
__peter__ at web.de
Mon Dec 7 13:59:54 EST 2015
Tony van der Hoff wrote:
> Hi,
>
> I have a class A, containing embedded embedded classes, which need to
> access methods from A.
> .
> A highly contrived example, where I'm setting up an outer class in a
> Has-a relationship, containing a number of Actors. The inner class needs
> to access a method of the outer class; here the method get_name.
>
> I don't really want to make Actor a sub-class (is-a; it isn't) of Monty;
> that would raise all sorts of other problems.
>
> Can anyone please advise me on how to achieve this magic?
>
> # define the outer class
> class Monty:
> def __init__( self, names ):
> self.actors = []
>
> i = 0
> for n in names:
> self.actors.append( Actor( n, i ) )
> i += 1 # here is a case for python supporting post-increment!
>
> def count_actors( self ):
> return len( self.actors )
>
> def list_actors( self ):
> h=[]
> for n in self.actors:
> h.append( n.get_name() )
> return h
>
> # define the inner class
> class Actor:
> def __init__ ( self, name, id ):
> self.name = name
> self.id = id
>
> def get_name( self ):
>
> # and here lies the problem;
> # AttributeError: Actor instance has no attribute 'count_actors'
> # how do I access the method in the enclosing class
> txt = "I'm Actor {} Number {} of {}".\
> format( self.name, self.id, self.count_actors() )
>
> # this works, of course
> #txt = "I'm Actor \"{}\"; Number {}. ".\
> format( self.name, self.id )
>
> return txt
>
> if __name__ == '__main__':
> o = Monty( ["Cleese", "Idle", "Palin" ] )
> print "number: ",o.count_actors()
> a = o.list_actors()
> for l in a:
> print l
I think I've seen the solution a long time a go in a Borland library -- a
Collection and a CollectionItem class, the latter with a reference to the
collection it belongs to. However, you are introducing a reference cycle,
and a simpler solution like putting a print_actor() method into the Monty
class is probably the way to go.
Anyway, here's a variant of your code using the back reference (and a few
cosmetical changes):
__metaclass__ = type # python 2 compatibility
class Monty:
def __init__(self, names):
self.actors = []
for id, name in enumerate(names, 1):
Actor(name, id, container=self)
def __len__(self):
return len(self.actors)
def __iter__(self):
for actor in self.actors:
yield actor
def remove(self, actor):
raise NotImplementedError
def add(self, actor):
self.actors.append(actor)
class Actor:
def __init__ (self, name, id, container=None):
self.name = name
self.id = id
self._container = None
self.container = container
def get_container(self):
return self._container
def set_container(self, container):
if self._container is not None:
self._container.remove(self)
if container is not None:
container.add(self)
self._container = container
container = property(get_container, set_container)
def __repr__(self):
return "I'm Actor {} Number {} of {}".format(
self.name, self.id, len(self.container))
if __name__ == '__main__':
o = Monty( ["Cleese", "Idle", "Palin" ])
print("number: {}".format(len(o)))
for l in o:
print(l)
More information about the Python-list
mailing list