First Summer 2008


Lecture 18: Object-Oriented Programming in Python.
Start with this example. An object is a data holder. Accessing data has specific syntax.

class Account(object):
    def __init__(self, initialBalance):
        self.balance = initialBalance
    

def main():
    a = Account(23)
    print a.balance
    a.balance = -23
    print a.balance
An object can hold more than data. It can also hold methods, which encapsulate behavior.

class Account(object):
    def __init__(self, initialBalance):
        self.balance = initialBalance
    def report(self):
        print "The current balance is:", self.balance
    

def main():
    a = Account(23)
    a.report()
    a.balance = -23
    a.report()
For safety data should be modified through a method, not directly.

class Account(object):
    def __init__(self, initialBalance):
        self.balance = initialBalance
    def report(self):
        print "The current balance is:", self.balance
    def set_balance(self, newBalance):
        self.balance = newBalance
    

def main():
    a = Account(23)
    a.report()
    a.set_balance(-23)
    a.report()
The advantage is that you can control what goes in, and may prevent inconsistent situations (will show that soon).

Take a look at the difference between get_balance() and report().

The difference is that between return and print.

Returning a value is what allows get_balance() to make its result available to report (the other way is impossible).

class Account(object):
    def __init__(self, initialBalance):
        self.set_balance(initialBalance)
    def report(self):
        print "The current balance is:", self.get_balance()
    def set_balance(self, newBalance):
        self.balance = newBalance
    def get_balance(self):
        return self.balance

def main():
    a = Account(23)
    a.report()
    a.set_balance(-23)
    a.report()
We can define a property now:
class Account(object):
    def __init__(self, initialBalance):
        self.__balance = initialBalance
    def report(self):
        print "The current balance is:", self.get_balance()
    def set_balance(self, newBalance):
        self.__balance = newBalance
    def get_balance(self):
        return self.__balance
    balance = property(get_balance, set_balance)

def main():
    a = Account(23)
    a.report()
    a.set_balance(-23)
    a.report()
I skipped a step here, by making the balance variable private.

We will see in a second what that means.

First here's the first benefit of a property, as defined:

class Account(object):
    def __init__(self, initialBalance):
        self.__balance = initialBalance
    def report(self):
        print "The current balance is:", self.get_balance()
    def set_balance(self, newBalance):
        if newBalance < 0:
            print "Sorry, the balance is not supposed to become negative."
        else:
            self.__balance = newBalance
    def get_balance(self):
        return self.__balance
    balance = property(get_balance, set_balance)

def main():
    a = Account(23)
    print a.balance
    a.balance = -23 # complains and does not change the balance 
    print a.balance
So now we have both the advantage of the simpler syntax as well as that of the procedural behavior.

Without the property this doesn't work at all:

class Account(object):
    def __init__(self, initialBalance):
        self.__balance = initialBalance
    def report(self):
        print "The current balance is:", self.get_balance()
    def set_balance(self, newBalance):
        if newBalance < 0:
            print "Sorry, the balance is not supposed to become negative."
        else:
            self.__balance = newBalance
    def get_balance(self):
        return self.__balance

def main():
    a = Account(23)
    print a.balance
    a.balance = -23
    print a.balance
Objects are available from outside as hash tables but their internal state is never in jeopardy.
class Account(object):
    def __init__(self, initialBalance):
        self.__balance = initialBalance
    def report(self):
        print "The current balance is:", self.get_balance()
    def set_balance(self, newBalance):
        if newBalance < 0:
            print "Sorry, the balance is not supposed to become negative."
        else:
            self.__balance = newBalance
    def get_balance(self):
        return self.__balance

def main():
    a = Account(23)
    a.__balance = -23 # does not work
    print a.__balance # does not work
    a.report() # prints 
Names without __ are available and modifiable from outside unless they're properties.

Names with __ are private and entirely accessible. Properties offer a perfect world. In exchange you need to stick with the method names.


Last updated: Jun 06, 2008 by Adrian German for A201/A597