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

Jean-Michel Pichavant jeanmichel at sequans.com
Mon Oct 18 13:01:29 EDT 2010


fab at slick.airforce-one.org wrote:
> Jean-Michel Pichavant <jeanmichel at sequans.com> 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.



More information about the Python-list mailing list