|
Spring Semester 2007
|
Lecture Eight: Private instance members. Accessors, mutators, properties.
Let's implement additional behavior for fractions.
|
Here's how a fraction can add (with another fraction).
|
class fraction(object):
def gcd(a, b):
m = max(abs(a), abs(b))
n = min(abs(a), abs(b))
if n == 0:
return 0
else:
d = n
while not (m % d == 0 and n % d == 0):
d -= 1
return d
gcd = staticmethod(gcd)
def __init__(self, num, den):
self.num = num / fraction.gcd(num, den)
self.den = den / fraction.gcd(num, den)
def __str__(self):
return str(self.num) + "/" + str(self.den)
def add(self, other):
return fraction(self.den * other.num + self.num * other.den, \
self.den * other.den)
Here's an example, too. |
One third plus two thirds should be equal to one.
|
>>> a = fraction(2,3)
>>> b = fraction(1,3)
>>> a.add(b)
<__main__.fraction object at 0x00D55150>
>>> print a.add(b)
1/1
>>>
The code changes now to accomodate private instance variables.
|
Note that we end up making more changes than we would first expect.
|
class fraction(object):
def gcd(a, b):
m = max(abs(a), abs(b))
n = min(abs(a), abs(b))
if n == 0:
return 0
else:
d = n
while not (m % d == 0 and n % d == 0):
d -= 1
return d
gcd = staticmethod(gcd)
def __init__(self, num, den):
self.__num = num / fraction.gcd(num, den)
self.__den = den / fraction.gcd(num, den)
def __str__(self):
return str(self.__num) + "/" + str(self.__den)
def add(self, other):
return fraction(self.__den * other.getNum() + self.__num * other.getDen(), \
self.__den * other.getDen())
def getNum(self):
return self.__num
def getDen(self):
return self.__den
Why is that necessary?
|
In this case it isn't, but how acess to the other fraction's numerator and denominator should be read only, no?
|
>>>
>>> a = fraction(2,3)
>>> a.__num
Traceback (most recent call last):
File "", line 1, in
a.__num
AttributeError: 'fraction' object has no attribute '__num'
>>> b = fraction(1,3)
>>> a.add(b)
<__main__.fraction object at 0x00D55EF0>
>>> print a.add(b)
1/1
>>> print fraction(2,6).add(fraction(5,3))
2/1
>>> print fraction(2,6)
1/3
>>> print fraction(5,3)
5/3
>>>
I see: some sort of hygienic perspective.
|
Profilaxy, if you want.
|
So access to private variables is completely closed outside the class?
|
No, not really; Python conventions only mean to discourage this type of access.
|
>>> a._fraction__num
2
>>> a = fraction(2,3)
>>> a._fraction__num
2
>>> a._fraction__den
3
>>>
Same goes for methods.
|
So we're now ready for a review and the new program.
|
Properties.
|
How can you quickly explain those?
|
It's only syntax, nothing deep.
|
Show me.
|
Here's come code that uses (defines) properties.
|
How does this work?
|
class critter(object):
def __init__(self):
self.__a = "first secret"
self.__b = "second secret"
def get_a(self):
return self.__a
def get_b(self):
return self.__b
def set_b(self, value):
self.__b = value
a = property(get_a)
b = property(get_b, set_b)
Here's how it works.
|
I see; just as you said, syntactic sugar, nothing more.
|
>>> x = critter()
>>> x.__a
Traceback (most recent call last):
File "<pyshell#127>", line 1, in
x.__a
AttributeError: 'critter' object has no attribute '__a'
>>> x._critter__a
'first secret'
>>> x._critter__a = "changed once"
>>> x._critter__a
'changed once'
>>> x.a
'changed once'
>>> x.a = 'changed again'
Traceback (most recent call last):
File "<pyshell#132>", line 1, in
x.a = 'changed again'
AttributeError: can't set attribute
>>> x.b
'second secret'
>>> x.b = 'changed once'
>>> x.b
'changed once'
>>> x.__b
Traceback (most recent call last):
File "<pyshell#136>", line 1, in
x.__b
AttributeError: 'critter' object has no attribute '__b'
>>> x._critter__b
'changed once'
>>> x._critter__b = 'changed again'
>>> x.b
'changed again'
>>>
Here's one more example, illustrating static variables.
|
Good. I think that's enough for today.
|
class critter(object):
total = 0
def __init__(self):
critter.total += 1
def test():
c = []
for i in range(10):
c.append(critter())
print critter.total
Same here.
|
See you in lab.
|
Files for the next chapter (lab this week):
|
We'll cover them in this order.
|
alien_blaster.py
playing_cards.py
playing_cards2.py
playing_cards3.py
games.py
simple_game.py
cards.py
blackjack.py
Updated by Adrian German for A202/A598