Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #100096 > unrolled thread

Accessing container's methods

Started byTony van der Hoff <tony@vanderhoff.org>
First post2015-12-07 18:10 +0000
Last post2015-12-09 12:04 +1100
Articles 20 on this page of 21 — 11 participants

Back to article view | Back to comp.lang.python


Contents

  Accessing container's methods Tony van der Hoff <tony@vanderhoff.org> - 2015-12-07 18:10 +0000
    Re: Accessing container's methods Rob Gaddi <rgaddi@highlandtechnology.invalid> - 2015-12-07 18:21 +0000
    Re: Accessing container's methods Michael Torrie <torriem@gmail.com> - 2015-12-07 11:36 -0700
      Re: Accessing container's methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-07 20:03 +0100
    Re: Accessing container's methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-07 19:46 +0100
    Re: Accessing container's methods Peter Otten <__peter__@web.de> - 2015-12-07 19:59 +0100
    Re: Accessing container's methods Ian Kelly <ian.g.kelly@gmail.com> - 2015-12-07 12:33 -0700
    Re: Accessing container's methods Terry Reedy <tjreedy@udel.edu> - 2015-12-07 16:38 -0500
    Re: Accessing container's methods Chris Angelico <rosuav@gmail.com> - 2015-12-08 09:02 +1100
    Re: Accessing container's methods Erik <python@lucidity.plus.com> - 2015-12-07 23:47 +0000
      Re: Accessing container's methods Tony van der Hoff <tony@vanderhoff.org> - 2015-12-08 12:35 +0000
      Re: Accessing container's methods [solved] Tony van der Hoff <tony@vanderhoff.org> - 2015-12-08 13:46 +0000
      Re: Accessing container's methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-08 20:02 +0100
        Re: Accessing container's methods Vincent Vande Vyvre <vincent.vande.vyvre@telenet.be> - 2015-12-08 20:54 +0100
          Re: Accessing container's methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-08 23:51 +0100
        Re: Accessing container's methods Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-12-08 20:30 +0000
          Re: Accessing container's methods Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-08 23:52 +0100
            Re: Accessing container's methods Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-12-08 22:59 +0000
        Re: Accessing container's methods Erik <python@lucidity.plus.com> - 2015-12-08 22:37 +0000
        Re: Accessing container's methods Ian Kelly <ian.g.kelly@gmail.com> - 2015-12-08 16:41 -0700
        Re: Accessing container's methods Chris Angelico <rosuav@gmail.com> - 2015-12-09 12:04 +1100

Page 1 of 2  [1] 2  Next page →


#100096 — Accessing container's methods

FromTony van der Hoff <tony@vanderhoff.org>
Date2015-12-07 18:10 +0000
SubjectAccessing container's methods
Message-ID<dcm0c2Fi2ktU1@mid.individual.net>
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

Thanks, Tony

[toc] | [next] | [standalone]


#100098

FromRob Gaddi <rgaddi@highlandtechnology.invalid>
Date2015-12-07 18:21 +0000
Message-ID<n44inp$6gj$1@dont-email.me>
In reply to#100096
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
>
> Thanks, Tony

Ideally, you wouldn't.  The Actor's name is independent of the number of
them in the Monty, and all logic that needed to know about the full
Monty would be there in list_actors, not delegated down to the Actor. 
That way all your dependencies are unidirectional: a Monty has a lot
of expectations about an Actor but an Actor knows nothing about a
Monty.

And that's GREAT when you can make it work.  Sometimes, in non-contrived
examples, you get a situation where you can't avoid blending information
around in both directions.  In that case, your Monty instance is already
acting as a factory for Actors.  Keep going with that; have the Actor be
init'ed with a .monty that refers back to the Monty containing it.  It's
a circular reference, but you can either a) break that using weakref or
b) not care and trust Python's garbage collection to sort it all out
eventually.

-- 
Rob Gaddi, Highland Technology -- www.highlandtechnology.com

Email address domain is currently out of order.  See above to fix.

[toc] | [prev] | [next] | [standalone]


#100099

FromMichael Torrie <torriem@gmail.com>
Date2015-12-07 11:36 -0700
Message-ID<mailman.26.1449513733.12405.python-list@python.org>
In reply to#100096
On 12/07/2015 11:10 AM, 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?

You could add an attribute to each embedded object that provides a
reference back to the container object.

All in all, this design has a kind of smell to it.  Would it not be
better to ask the container class for information about the children,
rather than the other way around?  If a piece of code holds a reference
to the child object then it must also by definition hold a reference to
the container object, so why can't it ask the container object directly?

[toc] | [prev] | [next] | [standalone]


#100102

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-07 20:03 +0100
Message-ID<9541165.BHaEqqM5qn@PointedEars.de>
In reply to#100099
Michael Torrie wrote:

> On 12/07/2015 11:10 AM, Tony van der Hoff wrote:
>> 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?
> 
> You could add an attribute to each embedded object that provides a
> reference back to the container object.

ACK.

> All in all, this design has a kind of smell to it.  Would it not be
> better to ask the container class for information about the children,
> rather than the other way around?  If a piece of code holds a reference
> to the child object then it must also by definition hold a reference to
> the container object, so why can't it ask the container object directly?

Indeed, in this example asking the parent would be the best approach because 
only the number of actors is requested.  That number should not change, and 
if it can change, then there should be an interface for that (a public 
method), in which the parent must update it.  So Monty.count_actors() does 
not have to count the actors each time it is called from Actor.get_name(); 
it just has to return the value of a private attribute containing the 
current count.

In other cases asking the parent would avoid inconsistencies, but that could 
be at the cost of efficiency; for example, a search for each child object, 
which does not scale well.

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail. 

[toc] | [prev] | [next] | [standalone]


#100100

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-07 19:46 +0100
Message-ID<90599474.m2LfGONAbA@PointedEars.de>
In reply to#100096
Tony van der Hoff wrote:

> I have a class A, containing embedded embedded classes, which need to
> access methods from A.

Let the name of the "embedded class" (which is not embedded at all in your 
example code) be E.  You could either store the information in the E 
instance upon or after construction, or you could pass a reference to the A 
instance to the E instance’s method, so that you can call the A instance’s 
public methods from the E instance’s methods.

But consider the Law of Demeter.

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

It would simply be wrong.  Monty (Python) is (literally) a group of Actors.
 
-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#100101

FromPeter Otten <__peter__@web.de>
Date2015-12-07 19:59 +0100
Message-ID<mailman.27.1449514812.12405.python-list@python.org>
In reply to#100096
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)


[toc] | [prev] | [next] | [standalone]


#100103

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-12-07 12:33 -0700
Message-ID<mailman.28.1449516863.12405.python-list@python.org>
In reply to#100096
On Mon, Dec 7, 2015 at 11:10 AM, Tony van der Hoff <tony@vanderhoff.org> 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?

I'm guessing that you're coming from Java. Java has two different
types of nested classes: non-static, where an instance of the inner
class is implicitly associated with an instance of the outer class;
and static, where an instance of the inner class is unrelated to any
instance of the outer class.

It looks like you're trying to do the former, but Python only has the
static type of nested classes. So how would you go about creating a
nested class of the non-static type? Make the association explicit.
When Monty creates an Actor, pass it self as one of the arguments.
Actor can then save that instance of Monty in an attribute and call
the method thusly.

As others have noted, this does create a reference cycle. The Python
garbage collector is fine with cleaning up reference cycles as long as
there are no objects __del__ methods anywhere in the cycle, so it's up
to you whether you consider that to be a problem or not.

[toc] | [prev] | [next] | [standalone]


#100109

FromTerry Reedy <tjreedy@udel.edu>
Date2015-12-07 16:38 -0500
Message-ID<mailman.31.1449524372.12405.python-list@python.org>
In reply to#100096
On 12/7/2015 1:10 PM, 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!

This is actually a case for using enumerate:
   for i, name in enumerate(names):

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

return list(self.actors)  # or perhaps even faster
return self.actors[:]

> # define the inner class
> class Actor:
>    def __init__ ( self, name, id ):
>      self.name = name
>      self.id = id

Tkinter, and I presume tk, works by creating circular references.
widgets get a reference to a master widget, and container get a 
reference to widgets that are placed (or packed or gridded) therein. 
Widgets have an explicit .destroy method (inherited from tcl/tk) to undo 
the circularity.  It works, but it is not completely without problems.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#100114

FromChris Angelico <rosuav@gmail.com>
Date2015-12-08 09:02 +1100
Message-ID<mailman.36.1449525755.12405.python-list@python.org>
In reply to#100096
On Tue, Dec 8, 2015 at 8:38 AM, Terry Reedy <tjreedy@udel.edu> wrote:
>>    def list_actors( self ):
>>      h=[]
>>      for n in self.actors:
>>        h.append( n.get_name() )
>>      return h
>
>
> return list(self.actors)  # or perhaps even faster
> return self.actors[:]

Not identical semantics. This is a use-case for a comprehension:

return [n.get_name() for n in self.actors]

(although I would eschew the getter in favour of just "n.name")

ChrisA

[toc] | [prev] | [next] | [standalone]


#100120

FromErik <python@lucidity.plus.com>
Date2015-12-07 23:47 +0000
Message-ID<mailman.41.1449532084.12405.python-list@python.org>
In reply to#100096
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.

[toc] | [prev] | [next] | [standalone]


#100148

FromTony van der Hoff <tony@vanderhoff.org>
Date2015-12-08 12:35 +0000
Message-ID<dco155F2qipU1@mid.individual.net>
In reply to#100120
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.

[toc] | [prev] | [next] | [standalone]


#100155 — Re: Accessing container's methods [solved]

FromTony van der Hoff <tony@vanderhoff.org>
Date2015-12-08 13:46 +0000
SubjectRe: Accessing container's methods [solved]
Message-ID<dco591F3qbqU1@mid.individual.net>
In reply to#100120
Hum, sorry about the empty reply; just finger trouble!

Anyway I wasn't expecting such a great response; thanks to all.

On 07/12/15 23:47, Erik wrote:
[snip]

> 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 ) )
>
Whilst I'm grateful for all the responses, this is the one that got me 
out of the hole I dug myself into.

In fact, this is precisely what I tried previously, and got:
TypeError: 'instancemethod' object has no attribute '__getitem__'

In my naivety, I concluded that this meant I couldn't use the 'self' 
pointer in this way. However, trying it with the Monty example, it 
worked fine, and I have now tracked down my error elsewhere.

>
> 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 ...
>
Yes, I guess it's quite nasty, but, in the non-trivial case, I'm only 
calling for dynamic data from the parent, and not modifying it in any 
way, so I think I can get away with it. Otherwise, I'd have to pass a 
vast list of initialization data to the (many) children, and keep that 
up to date by passing it down the line to each one, just in case it's 
required, which would slow down things excessively. I know that if a 
design doesn't feel comfortable, then it's probably wrong, but I believe 
that in this case it's probably the best way forward.

>
> 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 rather liked Terry's suggestion of using enumerate.

The comment was tounge-in-cheek: Referring to an earlier thread, I'm yet 
to be convinced that Python is better for not having 
pre/post-increment/decrement operators. But, hey, I'm sure better minds 
than mine have addressed the subject ;)

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

No, Im actually stuck on Python 2.7. I don't see how you jumped to that 
conclusion from a simple print statement.

On 07/12/15 21:38, Terry Reedy wrote:
[snip]
 > This is actually a case for using enumerate:
 >    for i, name in enumerate(names):
 >
I've not come across this previously, but shall certainly use it in 
future. Thanks!

 > return list(self.actors)  # or perhaps even faster
 > return self.actors[:]

That doesn't seem to work:
<__main__.Actor instance at 0x7fc7478ba560>
<__main__.Actor instance at 0x7fc7478ba5a8>
<__main__.Actor instance at 0x7fc7478ba5f0>


Anyway, I'm no longer in a hole; thanks for all the excellent help. I'll 
certainly review the design of my current project, to see if it can be 
improved.

Cheers, Tony

[toc] | [prev] | [next] | [standalone]


#100171

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-08 20:02 +0100
Message-ID<5516674.oipO6xLiNU@PointedEars.de>
In reply to#100120
Erik wrote:
^^^^
Please fix, Erik #75656.

> 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

NAK.  All kinds of objects already "know" which container they are in.

> (let alone its "index" or "key" in that container).

That is a different issue.

> Amongst other things, you can't put the object into multiple containers

You could if you made it a list of container references.

> 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

It is the container’s job to make sure that this does not happen.

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

You can.  Quickhack:

class Child:
    self._parents = []

    def add_to_parent (self, parent):
        self._parents.append(parent)
        self._parents = list(set(self._parents))

    def get_parents (self)
        return self._parents

class Parent:
    self._children = []

    def add_child (self, child):
        self._children.append(child)
        child.add_to_parent(self)

| >>> p = Parent()
| >>> c = Child()
| >>> p.add_child(c)
| >>> p2 = Parent()
| >>> p2.add_child(c)
| >>> c.get_parents()
| [p, p2]

“As a child, I want to know who my parents are.”

Certainly you will not deny the validity of that user story ;-)

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#100172

FromVincent Vande Vyvre <vincent.vande.vyvre@telenet.be>
Date2015-12-08 20:54 +0100
Message-ID<mailman.75.1449604867.12405.python-list@python.org>
In reply to#100171
Le 08/12/2015 20:02, Thomas 'PointedEars' Lahn a écrit :
> Erik wrote:
> ^^^^
> Please fix, Erik #75656.
>
>> 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
> NAK.  All kinds of objects already "know" which container they are in.
>
>> (let alone its "index" or "key" in that container).
> That is a different issue.
>
>> Amongst other things, you can't put the object into multiple containers
> You can.  Quickhack:
>
> class Child:
>      self._parents = []
>
>      def add_to_parent (self, parent):
>          self._parents.append(parent)
>          self._parents = list(set(self._parents))
>
>      def get_parents (self)
>          return self._parents
>
> class Parent:
>      self._children = []
> .....
I thing you should test your code before post it.

 >>> class Child:
...     self.parents = []
...
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "<stdin>", line 2, in Child
NameError: name 'self' is not defined

[toc] | [prev] | [next] | [standalone]


#100176

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-08 23:51 +0100
Message-ID<3619885.mg2BhAsQCr@PointedEars.de>
In reply to#100172
Vincent Vande Vyvre wrote:

> Le 08/12/2015 20:02, Thomas 'PointedEars' Lahn a écrit :
>> Erik wrote:
>>> Amongst other things, you can't put the object into multiple containers
>> You can.  Quickhack:
             ^^^^^^^^^
>> class Child:
>>      self._parents = []
>>
>>      def add_to_parent (self, parent):
>>          self._parents.append(parent)
>>          self._parents = list(set(self._parents))
>>
>>      def get_parents (self)
>>          return self._parents
>>
>> class Parent:
>>      self._children = []
>> .....
> I thing you should test your code before post it.

I _think_ you should read postings more carefully before replying to them.
 
>  >>> class Child:
> ...     self.parents = []
> ...
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
>    File "<stdin>", line 2, in Child
> NameError: name 'self' is not defined

Can be fixed easily by omitting “self.” there; likewise in Parent.  (In 
other programming languages I know, you need to refer to the class/instance 
explicitly to which you add attributes/properties.)

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#100173

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-12-08 20:30 +0000
Message-ID<mailman.76.1449606629.12405.python-list@python.org>
In reply to#100171
On 08/12/2015 19:02, Thomas 'PointedEars' Lahn wrote:
> Erik wrote:
> ^^^^
> Please fix, Erik #75656.
>

Please fix what?

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#100177

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-08 23:52 +0100
Message-ID<8148791.79CPUYHJkR@PointedEars.de>
In reply to#100173
Mark Lawrence wrote:

> On 08/12/2015 19:02, Thomas 'PointedEars' Lahn wrote:
>> Erik wrote:
>> ^^^^
>> Please fix, Erik #75656.
> 
> Please fix what?

You are not ready for the answer yet.

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#100179

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-12-08 22:59 +0000
Message-ID<mailman.79.1449615617.12405.python-list@python.org>
In reply to#100177
On 08/12/2015 22:52, Thomas 'PointedEars' Lahn wrote:
> Mark Lawrence wrote:
>
>> On 08/12/2015 19:02, Thomas 'PointedEars' Lahn wrote:
>>> Erik wrote:
>>> ^^^^
>>> Please fix, Erik #75656.
>>
>> Please fix what?
>
> You are not ready for the answer yet.
>

I'll be all pointed ears when you actually manage to provide an answer 
to anything here.

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#100175

FromErik <python@lucidity.plus.com>
Date2015-12-08 22:37 +0000
Message-ID<mailman.78.1449614324.12405.python-list@python.org>
In reply to#100171
Annoyingly, there seemed to be no responses to the original question 
when I wrote that and then shortly after, I saw all the others (and we 
all pretty much said the same thing - so I'm not sure why I was singled 
out for special attention ;)).

On 08/12/15 19:02, Thomas 'PointedEars' Lahn wrote:
> Erik wrote:
> ^^^^
> Please fix, Erik #75656.

Fixed(*)

Thomas 'PointerEars', you have chosen to selectively quote snippets of 
code and comments out of context, so I think it's futile to respond to 
those arguments individually. The original request (if you read it) was 
to return a string that said, essentially, "I am element 2 of 3 in my 
container".

You posted a "Quickhack" (which, to be fair, is an accurate description) 
which is incomplete, has errors and makes no sense in the context of the 
original question. We all know we can create a list in Python (of parent 
objects or whatever), but I think that if you expanded on that class a 
bit more (methods for the containers to update the contained objects on 
just what their index/key is etc) that you'll soon realise it's not a 
scalable option.

Also, WRT the original question, what is the method supposed to return 
now? "I am element 0 of 3 in container <FOO>, key 'bar' of ('bar', 
'foo', 'spam') in container <BAR>"? Just curious.

I'm interested in this response though:

 >> Generally, an object should not need to know which container it's in
 >
 > NAK.  All kinds of objects already "know" which container they are in.

Please elucidate. Examples from the standard library would be interesting.

E.

(*) In the sense that it's not going to change ;)

[toc] | [prev] | [next] | [standalone]


#100180

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-12-08 16:41 -0700
Message-ID<mailman.80.1449618128.12405.python-list@python.org>
In reply to#100171
On Tue, Dec 8, 2015 at 3:37 PM, Erik <python@lucidity.plus.com> wrote:
> On 08/12/15 19:02, Thomas 'PointedEars' Lahn wrote:
>>
>> Erik wrote:
>> ^^^^
>> Please fix, Erik #75656.
>
>
> Fixed(*)

[SNIP]

> (*) In the sense that it's not going to change ;)

Then I think you mean "Working as Intended", not "Fixed".  B-)

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.python


csiph-web