[Tutor] OOP class declaration question

Magnus Lycka magnus@thinkware.se
Thu Jan 9 06:42:02 2003


At 18:15 2003-01-08 -0600, Cameron Stoner wrote:
>Hi all,
>
>Recently I made a class that I found out wouldn't work properly unless all 
>the variables were filled with something.

A variable is ALWAYS a reference to an object. From
a technical point of view you can see it as a location
in a computers memory where you store an address to
another location in the memory, where some data is stored.
I imagine this is one more level of indirection than you
thought. This is the same whether you use classes or not.

It's probably more helpful if you see a variable as something
that points out an existing object, rather than as something
that you fill with an object. Let me explain why.

a = [1,2]
b = a
c = b

With the python code above, you have ONE list with the integers
1 and 2. There are three variables, but only one list object.
If you do b.append(5), and print c, it will show [1, 2, 5]. Right?

If you imagine c = b as filling the c variable with a list, you
get the wrong idea, right? c = b means that you make c point to
(or refer to) the same object in memory as the variable b (and a)
does. Right?

>   My question is why do you have to have all the fields filled with 
> something? Is it because you can't make an object of something without 
> knowing what each part is soposed to be?

This is really nothing particular for classes.

>  I thought python could allow for variable declaration on the fly and you 
> didn't have to worry about what type of data it was sopposed to hold.

No. You don't have varable declarations at all in
Python. You just define them. Compare with C etc.

int i; /* declaration of i */
...
i = 5; /* definition of i */

In python this is replaced with:

i = 5 # That's all folks!

It's completely pointless in Python to refer to a variable
before you have defined it. You have it all upside down. It's
in the OTHER programming languages, the ones with static
typing that allows you (well, forces you rather) to declare
variables before you use them.

It might feel confusing that not all attributes of the class
is listed in one place as in Java or C++, but that's life in
a dynamic language. You can add new attributes in runtime as
you like. There is no way for the class definition to know
about that. If this feels like a bad thing to you, have a look
at the new style classes in Python 2.2, and slots.

>Here is the code:
>
>class mobileSuit:
>  def __init__(self,lArm, rArm, head, lLeg, rLeg, back, maxHealth):
>    self.leftArmHealth = lArm
>    self.rightArmHealth = rArm
>    self.headHealth = head
>    self.leftLegHealth = lLeg
>    self.rightLegHealth = rLeg
>    self.backHealth = back
>    self.maxHealth = maxHealth

Just skip the next two lines. They are pointless. You don't
do declarations in Python.

>    self.healthPercent
>    self.actualHealth

Or, optionally, you might want to set these attributes to
some default value, that you use to indicate "undefined".
Maybe None?

>  #request overall health
>  def overallHealth(self, report):
>
>    #determine actualHealth
>    self.actualHealth = (self.leftArmHealth + self.rightArmHealth +
>     self.headHealth + self.leftLegHealth + self.rightLegHealth +
>     self.backHealth) / 6
>
>
>    #find percent of health
>    self.healthPercent = (self.actualHealth / self.maxHealth) * 100

Here you define these attributes. They don't need to exist
before you run this code.

How ever you do this, you will run into problems if you try
to access self.actualHealth or self.healthPercent before you
run the overallHealth method. If you set default values, whatever
code is fetching the attribute will get an irrelevant value, and
must be able to distinguish that. If you don't set any default
values, you will get AttributeError is you do something like...

testSuit = mobileSuit(6,6,6,6,6,6,6)
print testSuit.healthPercent

>    # report the status with a print else return the result
>    if report == 1:
>      print "The MS health is: ", self.healthPercent
>    else:
>      return self.healthPercent

But if this is the only way you intend to use "self.actualHealth"
and "self.healthPercent", you don't need the "self."-part, i.e.
you shouldn't make them attributes of the instance. Instance
attributes are only used when you want a value to persist between
method calls.

>testSuit = mobileSuit(6,6,6,6,6,6,6)

If I understand your intent correctly, you can simply do

class mobileSuit:
  def __init__(self,lArm, rArm, head, lLeg, rLeg, back, maxHealth):
    self.leftArmHealth = lArm
    self.rightArmHealth = rArm
    self.headHealth = head
    self.leftLegHealth = lLeg
    self.rightLegHealth = rLeg
    self.backHealth = back
    self.maxHealth = maxHealth

  #request overall health
  def overallHealth(self, report):

    #determine actualHealth
   actualHealth = (self.leftArmHealth + self.rightArmHealth +
     self.headHealth + self.leftLegHealth + self.rightLegHealth +
     self.backHealth) / 6.0 # Use a float unless you want to truncate.

    #find percent of health
   healthPercent = (actualHealth / self.maxHealth) * 100

    # report the status with a print else return the result
    if report:
      print "The MS health is: ", healthPercent
    else:
      return healthPercent

If you _do_ want the values calculated in overallHealth to persist,
I suggest that you call overallHealth in __init__ unless that leads
to bad performance. (Many million health records?) That way you will
allways have a reasonable value in those attributes.

Of course, if you change a used attribute, you need to call
overallHealth again.

x = mobileSuit(6,6,6,6,6,6,6)

x.overallHealth(1)
The MS health is:  100.0

print x.healthPercent
100.0

x.leftArmHealth = 3

print x.healthPercent
100.0

x.overallHealth(1)
The MS health is:  91.6666666667

print x.healthPercent
91.666666666666657

There are ways of calling overallHealth automagically whenever
an attribute in the class is changed, but that's not for today's
lecture...


-- 
Magnus Lycka, Thinkware AB
Alvans vag 99, SE-907 50 UMEA, SWEDEN
phone: int+46 70 582 80 65, fax: int+46 70 612 80 65
http://www.thinkware.se/  mailto:magnus@thinkware.se