Tags: %TAGME{ tpaction="" web="Main" tag="" }% view all tags

Classes, inheritance and object-oriented-programming

Classes revisited.

Python provides features that support object-oriented programming, including the ability to define new types or classes, which we saw in Lab 06. It is not easy to provide a crisp definition of object-oriented programming, but we have already seen some of its characteristics:

  • Programs are made up of object definitions and function definitions, and most of the computation is expressed in terms of operations on objects.
  • Each object definition corresponds to some object or concept in the real world, and the functions that operate on that object correspond to the ways real-world objects interact.
To quickly review what we covered on class definitions in Lab 06, let us define a very simple counter class (we used a similar class in your digit homework). This counter implements a physical clicker counter — the kind people use at entrances to events and buildings to count how many people are coming in.

class SimpleCounter: 
   def __init__(self): 
       self._count = 0

   def increment(self): 
       self._count += 1

   def clear(self): 
       self._count = 0

   def get_value(self): 
       return self._count

Copy this class definition into your Lab11.py file and run it in IPython. Then use the definition as follows.

my_counter = SimpleCounter()
my_counter.get_value()
my_counter.increment()
my_counter.increment()
my_counter.get_value()
my_counter.clear()
my_counter.get_value()

I hope you see that the counter starts off at 0, and that every increment operation bumps up the count by 1. The counter can be reset to zero and one can always read the current value of the counter using the get_value method.

Now we look at how we built this counter class. We give our new class a name, SimpleCounter. While not necessary, class names are usually capitalized by convention. We define four class methods: init, increment, clear, get_value.

Note that the first argument of each method is self. Python treats the first argument of a class method specially. It is assigned the value of the object to the left of the “.”, so, when you call c.increment(), it is interpreted as if you called increment(c) for the increment method of the SimpleCounter class. This argument does not need to be named self, but that is the convention used by most Python programmers to make it clear that it is the specific object that the method is operating on. Other than treating the first argument in this special way, class methods are just like any other Python function. They can take any number or type of arguments and return anything.

The init method is special. Python implements several “special” method names that get called when using certain operators. These methods all have names that begin and end with “__” to indicate they are not typically called directly. When do you think init gets called?

In the init method, the variable _count is defined as an instance variable (or field) contained within the object self. This _count variable is unique to every specific “instance” of the SimpleCounter class. (By convention such variables typically begin with the “_” character to indicate that they are instance variables. This is not necessary, however.) Try creating multiple counters. Increment them different amounts of times. Do they modify the same _count variable? Why or why not?

These are the basics of classes in Python. A class has a name and one or more methods. Once defined, a class becomes a new type. You may create as many objects of that type as you would like. Each object is an instance of the class type. Each instance contains its own data. The class methods operate on these instances to access and modify their data.

Exercise 1

Create a BankAccount class. Your class should support the following methods:

class BankAccount: 
    """Bank Account protected by a pin number."""

    def __init__(self, pin): 
        """Initial account balance is 0 and pin is 'pin'."""

    def deposit(self, pin, amount): 
        """Increment account balance by amount and return new balance."""

    def withdraw(self, pin, amount): 
        """Decrement account balance by amount and return amount withdrawn."""

    def get_balance(self, pin): 
        """Return account balance."""

    def change_pin(self, oldpin, newpin): 
        """Change pin from oldpin to newpin."""

As you implement your BankAccount class, you should think about the following:

  • What should be stored within the BankAccount class? That is, what are its instance variables?
  • What should happen if the wrong pin is provided for any of the methods (other than init, which is setting the initial pin)?
  • What should happen if you try to withdraw more than is in the account?
Does your bank account behave as you expect? Try depositing and/or withdrawing change, instead of whole dollar amounts. Do you want your real bank account to behave this way?
Topic revision: r1 - 2020-07-27 - JimSkon
 
This site is powered by the TWiki collaboration platform Powered by PerlCopyright © 2008-2020 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback