Classes in a class: how to access variables from one in another

Discussion in 'Python' started by Guest, Oct 18, 2010.

  1. Guest

    Guest Guest

    Hello.

    I have a class A that contains two classes B and C:

    class A:
    class B:
    self.x = 2

    class C:

    Is there a way to access the x defined in B in class C?

    Thanks.

    --
    F. Delente
     
    Guest, Oct 18, 2010
    #1
    1. Advertising

  2. Guest

    Neil Cerutti Guest

    On 2010-10-18, <-one.org> <-one.org> wrote:
    > Hello.
    >
    > I have a class A that contains two classes B and C:
    >
    > class A:
    > class B:
    > self.x = 2
    >
    > class C:
    >
    > Is there a way to access the x defined in B in class C?


    That's not valid Python code. Do you mean:

    Class A:
    Class B:
    x = 2

    or

    Class A:
    Class B:
    def __init__(self):
    self.x = 2

    --
    Neil Cerutti
     
    Neil Cerutti, Oct 18, 2010
    #2
    1. Advertising

  3. Guest

    Neil Cerutti Guest

    On 2010-10-18, Neil Cerutti <> wrote:
    > On 2010-10-18, <-one.org> <-one.org> wrote:
    >> Hello.
    >>
    >> I have a class A that contains two classes B and C:
    >>
    >> class A:
    >> class B:
    >> self.x = 2
    >>
    >> class C:
    >>
    >> Is there a way to access the x defined in B in class C?

    >
    > That's not valid Python code. Do you mean:
    >
    > Class A:
    > Class B:
    > x = 2
    >
    > or
    >
    > Class A:
    > Class B:
    > def __init__(self):
    > self.x = 2


    Oops! Python has no Class.

    --
    Neil Cerutti
     
    Neil Cerutti, Oct 18, 2010
    #3
  4. Guest

    Guest Guest

    Neil Cerutti <> wrote:
    >> I have a class A that contains two classes B and C:
    >>
    >> class A:
    >> class B:
    >> self.x = 2
    >>
    >> class C:


    I only wanted to show the structure of the code, not the actual
    instructions.

    > That's not valid Python code. Do you mean:
    >
    > Class A:
    > Class B:
    > x = 2


    > Class A:
    > Class B:
    > def __init__(self):
    > self.x = 2
    >


    Any of these, aslong as I can access x in C.

    By the way, is the first proposition (that is, x = 2, without the
    self.) valid? Is x a global variable then?

    Thanks.

    --
    F. Delente
     
    Guest, Oct 18, 2010
    #4
  5. Guest

    Gary Herron Guest

    On 10/18/2010 06:45 AM, -one.org wrote:
    > Neil Cerutti<> wrote:
    >>> I have a class A that contains two classes B and C:
    >>>
    >>> class A:
    >>> class B:
    >>> self.x = 2
    >>>
    >>> class C:

    > I only wanted to show the structure of the code, not the actual
    > instructions.
    >
    >> That's not valid Python code. Do you mean:
    >>
    >> Class A:
    >> Class B:
    >> x = 2
    >> Class A:
    >> Class B:
    >> def __init__(self):
    >> self.x = 2
    >>

    > Any of these, aslong as I can access x in C.
    >
    > By the way, is the first proposition (that is, x = 2, without the
    > self.) valid? Is x a global variable then?
    >
    > Thanks.
    >

    Well, your code still doesn't make sense, but the generic answers are:

    This defines a class variable:
    class A:
    x=123
    and access to the variable is
    A.x

    This defines an instance variable:
    class A:
    def __init__(self):
    self.x = 123
    and once you have an object of class A,
    a = A()
    access is
    a.x
    from outside the class, and
    self.x
    from inside the class.
    (Those are really the same, the instance is named 'a' in one case and
    'self' in the other.)

    If *any* object, class or instance of a class (or module or whatever)
    contains another, access is by chaining the dots.
    OuterOb.InnerOb.attribute


    Hope that answers your question.

    Gary Herron
     
    Gary Herron, Oct 18, 2010
    #5
  6. Guest

    Guest Guest

    Gary Herron <> wrote:
    > Well, your code still doesn't make sense, but the generic answers are:


    I'll clarify what I need then:

    I'm drawing Bézier curves. I draw them on a zone that is defined as a
    subclass of GtkDrawingArea.

    In a zone, I define a system of coordinates by 4 values: xmin, xmax,
    ymin, and ymax that define the viewing port.

    A curve is defined in this system of coordinates by a collection of
    points.

    So my way of coding it is the following:

    class zone(GtkDrawingArea):

    class systemOfCoordinates:
    self.xmin = -5
    self.xmax = 5
    self.ymin = -5
    self.ymax = 5

    class Curve:
    self.listOfPoints = ()

    def draw(self):
    pass
    # for each point in self.listOfPoints: draw this point
    # then draw the Bézier curve passing through these points

    class Point:
    def __init__(self, x, y):
    (self.x, self.y) = (x, y)

    def draw(self):
    # ... code for drawing a dot in the system of coordinates...

    def __init__(self): # for the zone object
    self.coord = self.systemOfCoordinates()
    self.listOfCurves = ( self.Curve() )

    def expose(self, widget, event):
    pass
    # for each curve of self.listOfCurves: draw it

    Now to actually draw the dot on the screen, I need to access
    coord.xmin, coord.xmax, coord.ymin and coord.ymax to Point.draw(). I
    could do this by passing a reference to Point.draw(), but I'd like to
    do this implicitely.

    I guess that in that case, xmin, xmax, ymin and ymax should be class variables of zone, right?

    > If *any* object, class or instance of a class (or module or whatever)
    > contains another, access is by chaining the dots.
    > OuterOb.InnerOb.attribute
    >
    > Hope that answers your question.


    This should help, I'll make some tests.

    Thanks.

    --
    F. Delente
     
    Guest, Oct 18, 2010
    #6
  7. -one.org wrote:
    > Neil Cerutti <> wrote:
    >
    >>> I have a class A that contains two classes B and C:
    >>>
    >>> class A:
    >>> class B:
    >>> self.x = 2
    >>>
    >>> class C:
    >>>

    >
    > I only wanted to show the structure of the code, not the actual
    > instructions.
    >
    >


    Always post working code, or at least something we can paste in the
    python interpreter (even if it's buggy)

    class A:
    class B:
    x=2
    class C:
    def __init__(self):
    print A.B.x

    c = A.C()

    >2


    JM
     
    Jean-Michel Pichavant, Oct 18, 2010
    #7
  8. Guest

    Guest Guest

    Jean-Michel Pichavant <> wrote:
    > Always post working code, or at least something we can paste in the
    > python interpreter (even if it's buggy)


    Ok, noted.

    > class A:
    > class B:
    > x=2
    > class C:
    > def __init__(self):
    > print A.B.x
    >
    > c = A.C()
    >
    > >2


    Good, thanks.

    I've made further tests and here is what I have come to:

    class zoneDeDessin(gtk.DrawingArea):
    xmin = -5.5
    xmax = 5.5
    ymin = -5.5
    ymax = 5.5

    class Handle:
    def __init__(self, xEcran, yEcran):
    (self.xEcran, self.yEcran) = (xEcran, yEcran)
    (self.xRepere, self.yRepere) = (zoneDeDessin.XdeLEcranAuRepere(xEcran), zoneDeDessin.YdeLEcranAuRepere(yEcran))

    def __init__(self):
    gtk.DrawingArea.__init__(self)
    (self.largeur, self.hauteur) = (0,0)

    def expose(self, widget, event):
    rect = self.get_allocation()
    (self.largeur, self.hauteur) = (rect.width, rect.height)

    def XdeLEcranAuRepere(self, x):
    return zoneDeDessin.xmin+x*(zoneDeDessin.xmax-zoneDeDessin.xmin)/float(self.largeur)
    def YdeLEcranAuRepere(self, y):
    return zoneDeDessin.ymax+y*(zoneDeDessin.ymin-zoneDeDessin.ymax)/float(self.hauteur)

    I have further code that should add a Handle when I double-click on
    the screen.

    However I get this error when executing:

    Traceback (most recent call last):
    File "./zoneDeDessin.py", line 161, in boutonRelache
    zoneDeDessin.Courbe.ajouterUnHandle(self.courbeCourante, event.x, event.y)
    File "./zoneDeDessin.py", line 36, in ajouterUnHandle
    self.listeDesPoints.append(zoneDeDessin.Handle(xEcran, yEcran))
    File "./zoneDeDessin.py", line 22, in __init__
    (self.xRepere, self.yRepere) = (zoneDeDessin.XdeLEcranAuRepere(xEcran), zoneDeDessin.YdeLEcranAuRepere(yEcran))
    TypeError: unbound method XdeLEcranAuRepere() must be called with zoneDeDessin instance as first argument (got float instance instead)

    I understand the error (XdeLEcranAuRepere is an instance method, not a
    class method), but I don't see how to fix it, except by making largeur
    and hauteur class variables...

    Any hint?

    Thanks!

    --
    F. Delente
     
    Guest, Oct 18, 2010
    #8
  9. Guest

    Nobody Guest

    On Mon, 18 Oct 2010 14:35:58 +0000, fab wrote:

    > So my way of coding it is the following:
    >
    > class zone(GtkDrawingArea):
    >
    > class systemOfCoordinates:
    > self.xmin = -5
    > self.xmax = 5
    > self.ymin = -5
    > self.ymax = 5


    "self" isn't meaningful within a class definition.

    It's far from clear what the intent of your code is.

    It's not even clear whether you understand the difference between a
    class and an object.

    >
    > class Curve:
    > self.listOfPoints = ()


    "self" isn't meaningful within a class definition.

    > def draw(self):
    > pass
    > # for each point in self.listOfPoints: draw this point
    > # then draw the Bézier curve passing through these points


    In light of this, I'add assume that the above:

    > class Curve:
    > self.listOfPoints = ()


    should have been:

    class Curve:
    def __init__(self):
    self.listOfPoints = ()

    This will give each *instance* of Curve a member named "listOfPoints".

    > def __init__(self): # for the zone object
    > self.coord = self.systemOfCoordinates()
    > self.listOfCurves = ( self.Curve() )


    I suspect that you should use a list [...] rather than a tuple (...) here.
    The main difference is that you can modify a list, but you can't modify a
    tuple.

    > Now to actually draw the dot on the screen, I need to access
    > coord.xmin, coord.xmax, coord.ymin and coord.ymax to Point.draw(). I
    > could do this by passing a reference to Point.draw(), but I'd like to
    > do this implicitely.
    >
    > I guess that in that case, xmin, xmax, ymin and ymax should be class
    > variables of zone, right?


    Not if you want to have more than one instance of zone. Class variables
    are effectively global, i.e. you only have one set of variables regardless
    of how many instances of the class you create. Putting them into a class
    simply avoids "polluting" the module's top-level namespace.

    If you don't want to pass the systemOfCoordinates to Point.draw, pass it
    to Point.__init__. Or pass a reference to the zone to either of these.

    If you're assuming that instances of a nested class get an implicit
    reference to some instance of the outer class, you're mistaken.

    Nested classes are simply a scoping feature, i.e. the name of the inner
    class is added to the outer class' dictionary, not to the module's
    dictionary. Other than that, the situation is no different than if the
    inner class had been declared at the top level.

    If you want objects to have a reference to some "parent" entity, you have
    to explicitly pass the reference to the constructor and store it as an
    instance member.
     
    Nobody, Oct 18, 2010
    #9
  10. Guest

    Guest Guest

    Christian Heimes <> wrote:
    > Don't nest classes. Just don't. This might be a valid and good approach
    > in some programming languages but it's not Pythonic. Your code can
    > easily be implemented without nested classes.


    I think you're right. It would have been more aesthetically pleasant
    to me (a Handle has only sense on a drawing zone), but if it's more
    complicated I'll avoid nested classes.

    --
    F. Delente
     
    Guest, Oct 18, 2010
    #10
  11. On Mon, 18 Oct 2010 17:17:52 +0200 Christian Heimes <>
    wrote:

    > [snip]
    > Don't nest classes. Just don't. This might be a valid and good
    > approach in some programming languages but it's not Pythonic.


    Explain!

    /W


    --
    To reach me via email, replace INVALID with the country code of my home
    country. But if you spam me, I'll be one sour Kraut.
     
    Andreas Waldenburger, Oct 18, 2010
    #11
  12. -one.org wrote:
    > Jean-Michel Pichavant <> wrote:
    >
    >> Always post working code, or at least something we can paste in the
    >> python interpreter (even if it's buggy)
    >>

    >
    > Ok, noted.
    >
    >
    >> class A:
    >> class B:
    >> x=2
    >> class C:
    >> def __init__(self):
    >> print A.B.x
    >>
    >> c = A.C()
    >>
    >>
    >>> 2
    >>>

    >
    > Good, thanks.
    >
    > I've made further tests and here is what I have come to:
    >
    > class zoneDeDessin(gtk.DrawingArea):
    > xmin = -5.5
    > xmax = 5.5
    > ymin = -5.5
    > ymax = 5.5
    >
    > class Handle:
    > def __init__(self, xEcran, yEcran):
    > (self.xEcran, self.yEcran) = (xEcran, yEcran)
    > (self.xRepere, self.yRepere) = (zoneDeDessin.XdeLEcranAuRepere(xEcran), zoneDeDessin.YdeLEcranAuRepere(yEcran))
    >
    > def __init__(self):
    > gtk.DrawingArea.__init__(self)
    > (self.largeur, self.hauteur) = (0,0)
    >
    > def expose(self, widget, event):
    > rect = self.get_allocation()
    > (self.largeur, self.hauteur) = (rect.width, rect.height)
    >
    > def XdeLEcranAuRepere(self, x):
    > return zoneDeDessin.xmin+x*(zoneDeDessin.xmax-zoneDeDessin.xmin)/float(self.largeur)
    > def YdeLEcranAuRepere(self, y):
    > return zoneDeDessin.ymax+y*(zoneDeDessin.ymin-zoneDeDessin.ymax)/float(self.hauteur)
    >
    > I have further code that should add a Handle when I double-click on
    > the screen.
    >
    > However I get this error when executing:
    >
    > Traceback (most recent call last):
    > File "./zoneDeDessin.py", line 161, in boutonRelache
    > zoneDeDessin.Courbe.ajouterUnHandle(self.courbeCourante, event.x, event.y)
    > File "./zoneDeDessin.py", line 36, in ajouterUnHandle
    > self.listeDesPoints.append(zoneDeDessin.Handle(xEcran, yEcran))
    > File "./zoneDeDessin.py", line 22, in __init__
    > (self.xRepere, self.yRepere) = (zoneDeDessin.XdeLEcranAuRepere(xEcran), zoneDeDessin.YdeLEcranAuRepere(yEcran))
    > TypeError: unbound method XdeLEcranAuRepere() must be called with zoneDeDessin instance as first argument (got float instance instead)
    >
    > I understand the error (XdeLEcranAuRepere is an instance method, not a
    > class method), but I don't see how to fix it, except by making largeur
    > and hauteur class variables...
    >
    > Any hint?
    >
    > Thanks!
    >
    >

    Quite simple in fact,

    XdeLEcranAuRepere is an instance method (any method with self as 1st parameter is an instance method).

    However you called it as a class method: zoneDeDessin.XdeLEcranAuRepere(xEcran)
    Just change that code to self.XdeLEcranAuRepere(xEcran). 'self' allows you to access attributes and methods of an instance.

    Also don't code in french, you use meaningful names which is good, but they're meaninful only to french speaking people. That will reduce the help you can't get in this international list for instance.

    Another detail, my guess is that
    xmin = -5.5
    xmax = 5.5
    ymin = -5.5
    ymax = 5.5


    should be instance attributes not class attributes (you don't want 2 instances of zoneDeDessin sharing the same xmin value).
    A classic pattern for default values is:


    class DrawArea:
    DFT_XMIN = -5.5
    DFT_XMAX = 5.5
    DFT_YMIN = -5.5
    DFT_YMAX = 5.5

    def __init__(self, xmin=None, xmax=None, ymin=None, ymax=None):
    self.xmin=xmin
    self.xmax=xmax
    self.ymin=ymin
    self.ymax=ymax
    for attribute in ['xmin', 'xmax', 'ymin', 'ymax']:
    if getattr(self, attribute) is None: # then let's assign the default value
    setattr(self, attribute, getattr(self, 'DFT_' + attribute.upper())) # there's a little bit of magic here, it could be improved but this is not the purpose here

    d1=DrawArea()
    print 'd1 ', d1.__dict__
    d2=DrawArea(xmax=8)
    print 'd2 ', d2.__dict__

    execution output:
    d1 {'xmin': -5.5, 'ymin': -5.5, 'ymax': 5.5, 'xmax': 5.5}
    d2 {'xmin': -5.5, 'ymin': -5.5, 'ymax': 5.5, 'xmax': 8}

    JM


    PS : to those how would wonder why not include self.xmin=xmin into the
    'for attribute' loop, it's just to not mess with most linter(including
    pylint), and for attributes, it's always a good think to 'declare' them
    explicitly in the __init__ method.
     
    Jean-Michel Pichavant, Oct 18, 2010
    #12
  13. Guest

    John Nagle Guest

    On 10/18/2010 8:17 AM, Christian Heimes wrote:
    > Am 18.10.2010 16:35, schrieb -one.org:
    >> So my way of coding it is the following:
    >>
    >> class zone(GtkDrawingArea):
    >>
    >> class systemOfCoordinates:
    >> self.xmin = -5
    >> self.xmax = 5
    >> self.ymin = -5
    >> self.ymax = 5
    >>
    >> class Curve:
    >> self.listOfPoints = ()
    >>
    >> def draw(self):
    >> pass


    No, that's not the way to do it. You're not clear on the
    difference between a class and an object instance. Data
    is normally stored in object instances, not classes themselves.
    (You can store data in a class itself, but that's just creates a single
    global variable. That's rarely done.)

    Something like this is more usual:

    class SystemOfCoordinates(object) :

    def __init__(self, xmin, xmax, ymin, ymax) :
    self.xmin = xmin
    self.xmax = xmax
    self.ymin = ymin
    self.ymax = ymax

    class Curve(object) :
    ...


    class Zone(GtkDrawingArea) :

    def __init__(self, xmin, xmax, ymin, ymax)
    self.coords = SystemOfCoordinates(xmin, xmax, ymin, ymax)

    ....

    myzone = Zone(0,200,0,200) # make a Zone
    ....
    myzone.Curve(....)
    ....
    myzone.draw()



    When you call Zone like that, an empty Zone object is created and the
    __init__ function of Zone is called to fill it. That function in turn
    calls SystemOfCoordinates, which calls the __init__ function of
    SystemOfCoordinates, which returns a SystemOfCoordinates object.
    That's stored in "self.coords", a data attribute of the Zone object.
    You get back a filled-in Zone object, which you can then use.

    John Nagle
     
    John Nagle, Oct 18, 2010
    #13
  14. On Mon, 18 Oct 2010 17:17:52 +0200, Christian Heimes wrote:

    > Don't nest classes. Just don't. This might be a valid and good approach
    > in some programming languages but it's not Pythonic. Your code can
    > easily be implemented without nested classes.


    I'll accept that nested classes are unusual, but unPythonic? Never!
    Here's a contrived example:

    class K:
    class Data(tuple):
    def __init__(self, t):
    a, b, c = t
    self.a = a
    self.b = b
    self.c = c
    def spam(self, a, b, c):
    self.data = type(self).Data([a,b,c])


    Of course, in Python 2.6 this *specific* example is better written using
    namedtuple, but namedtuple is just a factory function for returning a
    class!

    class K:
    # One-liner to create a nested class.
    Data = namedtuple("Data", "a b c")
    ...


    Either way, now you can subclass K by changing Data, without exposing
    your private, internal classes to the rest of the module:

    class K2(K):
    class Data(K.Data):
    def __init__(self, t):
    t = (int(x) for x in t)
    super(Data, self).__init__(t)


    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #14
  15. On Mon, 18 Oct 2010 09:34:07 -0700, Chris Rebert wrote:

    > Also, Python's scoping rules, particularly for class-level scopes, don't
    > work the way programmers from languages where nested classes are common
    > would expect:

    [snip example]


    I'm sorry, I don't see that "language Foo programmers will be surprised
    that Python is not language Foo" is an argument against Python
    programmers using nested classes. Surely it's an argument against writing
    Foo in Python?



    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #15
  16. On Mon, 18 Oct 2010 09:34:07 -0700, Chris Rebert wrote:

    > Also, Python's scoping rules, particularly for class-level scopes, don't
    > work the way programmers from languages where nested classes are common
    > would expect:

    [snip example]


    I'm sorry, I don't see that "language Foo programmers will be surprised
    that Python is not language Foo" is an argument against Python
    programmers using nested classes. Surely it's an argument against writing
    Foo in Python?



    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #16
  17. On Mon, 18 Oct 2010 09:34:07 -0700, Chris Rebert wrote:

    > Also, Python's scoping rules, particularly for class-level scopes, don't
    > work the way programmers from languages where nested classes are common
    > would expect:

    [snip example]


    I'm sorry, I don't see that "language Foo programmers will be surprised
    that Python is not language Foo" is an argument against Python
    programmers using nested classes. Surely it's an argument against writing
    Foo in Python?



    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #17
  18. On Mon, 18 Oct 2010 09:34:07 -0700, Chris Rebert wrote:

    > Also, Python's scoping rules, particularly for class-level scopes, don't
    > work the way programmers from languages where nested classes are common
    > would expect:

    [snip example]


    I'm sorry, I don't see that "language Foo programmers will be surprised
    that Python is not language Foo" is an argument against Python
    programmers using nested classes. Surely it's an argument against writing
    Foo in Python?



    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #18
  19. On Mon, 18 Oct 2010 09:34:07 -0700, Chris Rebert wrote:

    > Also, Python's scoping rules, particularly for class-level scopes, don't
    > work the way programmers from languages where nested classes are common
    > would expect:

    [snip example]


    I'm sorry, I don't see that "language Foo programmers will be surprised
    that Python is not language Foo" is an argument against Python
    programmers using nested classes. Surely it's an argument against writing
    Foo in Python?



    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #19
  20. On Mon, 18 Oct 2010 09:34:07 -0700, Chris Rebert wrote:

    > Also, Python's scoping rules, particularly for class-level scopes, don't
    > work the way programmers from languages where nested classes are common
    > would expect:

    [snip example]


    I'm sorry, I don't see that "language Foo programmers will be surprised
    that Python is not language Foo" is an argument against Python
    programmers using nested classes. Surely it's an argument against writing
    Foo in Python?



    --
    Steven
     
    Steven D'Aprano, Oct 18, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. vinuta
    Replies:
    1
    Views:
    371
    =?Utf-8?B?S29zdGFkaW4gS29zdG92?=
    Jan 31, 2005
  2. lonelyplanet999
    Replies:
    1
    Views:
    2,230
    VisionSet
    Nov 13, 2003
  3. marekw2143
    Replies:
    3
    Views:
    1,366
    marekw2143
    Jul 25, 2009
  4. Robert Cohen
    Replies:
    3
    Views:
    280
    Andrew Durstewitz
    Jul 15, 2003
  5. xodepp shrestha
    Replies:
    3
    Views:
    258
    Gene Wirchenko
    Feb 21, 2013
Loading...

Share This Page