Path: csiph.com!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Tony van der Hoff Newsgroups: comp.lang.python Subject: Re: Accessing container's methods Date: Tue, 8 Dec 2015 12:35:48 +0000 Lines: 80 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net 6xt9i1ieI37Ai1Bd0xW4wwqno10dgjDleIrF7o1E5FrFoQBpOa Cancel-Lock: sha1:gJ4VtiBVyhm6bJ0Qp6RHH3HXz5Y= User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Icedove/38.4.0 In-Reply-To: Xref: csiph.com comp.lang.python:100148 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.