On 07/12/15 23:47, Erik wrote:
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.

--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to