Accessing container's methods

Erik python at lucidity.plus.com
Mon Dec 7 18:47:26 EST 2015


Hi Tony,

On 07/12/15 18:10, Tony van der Hoff wrote:
> 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.

Generally, an object should not need to know which container it's in 
(let alone its "index" or "key" in that container). Amongst other 
things, you can't put the object into multiple containers which might be 
organised differently and you are asking for bugs where the container 
and the object get out of sync WRT just where the object is in the 
container (in your example, if you found you wanted to add a method 
where the 'actors' list is modified (say, calling "self.actors.insert(3, 
...)", or sorting the list) then things get nasty quickly.

However, you've said this is a highly contrived example, so I'll bear 
with you and assume what you're trying to do is not quite as nasty as 
the example implies ;)

> Can anyone please advise me on how to achieve this magic?

As you can't sensibly put the object into more than one container at a 
time anyway, then you can pass the container object to the Actor object 
as its "parent". It can then call its parent object for things that the 
parent will know (such as, the total number of contained objects):

class Actor:
    def __init__ ( self, name, id, parent ):
      self.name = name
      self.id = id
      self.parent = parent

    def get_name( self ):
      txt = "I'm Actor {} Number {} of {}".\
               format(  self.name, self.id, self.parent.count_actors() )
      return txt

Then you can add a new actor with:

   self.actors.append( Actor( n, i, self ) )


Note that you are creating circular references here, too (the container 
references the Actor object and the Actor object references the 
container). Just another possible issue to bear in mind ...


Also, while I'm looking at this, you have this loop and comment:

 >    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!

However, if you refactor that loop to use iterators, you don't need to 
manually manipulate 'i' at all (you need to import the itertools module 
first, and this is the "new" version where the container is passed in as 
the parent):

     def __init__( self, names ):
       self.actors = [ Actor ( n, i, self ) for n, i in 
itertools.izip(names, itertools.count()) ]

Or, if you don't like list comprehensions:

     def __init__( self, names ):
       self.actors = []
       for n, i in itertools.izip(names, itertools.count()):
         self.actors.append( Actor( n, i, self ) )

(I assume you're using Python 3 because of your print statement - in 
Python 3, 'itertools.izip' should just be 'zip'.)
HTH,
E.



More information about the Python-list mailing list