[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