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

G

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

Neil Cerutti

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
 
G

Guest

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

Gary Herron

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

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
 
G

Guest

Gary Herron said:
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.
 
J

Jean-Michel Pichavant

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

JM
 
G

Guest

Jean-Michel Pichavant said:
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()

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

Nobody

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

Guest

Christian Heimes said:
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.
 
J

Jean-Michel Pichavant

Ok, noted.



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

John Nagle

Am 18.10.2010 16:35, schrieb (e-mail address removed)-one.org:

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
 
S

Steven D'Aprano

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

Steven D'Aprano

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

Steven D'Aprano

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

Steven D'Aprano

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

Steven D'Aprano

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

Steven D'Aprano

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

Steven D'Aprano

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?
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top