[Tutor] Questions about classes

Steven D'Aprano steve at pearwood.info
Tue Nov 13 13:57:47 CET 2012


On 13/11/12 13:49, brandon w wrote:


> 1. I saw in the book an assignment written like this:
>
> class HumanBeing:
>          def makeName(self, name):
>                    *self.name = name*
> *
> *
> Why is it not written like this?:
>
> class HumanBeing:
>          def makeName(self, name):
> *                  name = self.name*

This creates a class called "HumanBeing". It includes a method called
"makeName". Methods are very similar to functions, the differences will
become clear further on.

Methods are defined in the same way as functions: the "def" keyword,
followed by the name of method, then the parameters. Each parameter
creates a local variable, so the "makeName" method has two local
variables:

- self
- name

"self" is special. When you call the method, Python will automatically
provide the "self" argument. So if you do this:

fred = HumanBeing()  # create an instance of HumanBeing class
fred.makeName("flintstone")

the makeName method gets passed two arguments:

- self = fred, provided automatically by Python
- name = "flintstone", provided by you


Now, inside the body of the method, we have this:

self.name = name

That says:

- take the argument *name* (which has value "flintstone")
- attach it to the instance *self* using the attribute called "name"

After the line finishes executing, the instance *fred* will now have
an attribute *name* with value "flintstone".

So if you later call:

print(fred.name)

Python will print "flintstone".

What if it were written the other way, as you suggested?

name = self.name

That goes in the opposite direction: first Python tries to look up
an attribute called name. It probably doesn't find one, and so it
will raise an exception and print an error message. But let's
suppose it did find one. It then takes that value and stores it
in the local variable "name", over-writing the local variable you
provided as an argument to the method.

Then, when the method returns (either at a "return" statement, or
by reaching the end of the method), the local variable is
forgotten and no permanent change is made.



> 2. Why use a class in the first place? What is the purpose of constructing
> a class instead of just writing a program with a bunch of functions?

Classes are useful for a couple of reasons:

1) Encapsulation

A class keeps together related code and data. A good example comes from the
Python built-in class "list". The list class combines:

- a storage area for the list data;
- methods which operate on that list data.

For example, lists have a method "index". But strings also have a method
called "index". The list.index method knows how to search a list. It knows
nothing about strings, and doesn't need to care about strings. It only
needs to care about lists. The str.list method knows how to search a string.
It knows nothing about lists, and only cares about strings. That makes it
much easier to program. Instead of one giant function:


def index(obj, value):
     if obj is a string:
         code for searching strings
     elif obj is a list:
         code for searching lists
     elif obj is a tuple:
         code for searching tuples
     else:
         raise TypeError("don't know how to index obj")

instead each branch of the function gets encapsulated into a str class, a
list class, a tuple class, and anything else that you might want to index.
If you write a Book class, you can give it an index method without needing
to care about lists, strings, tuples, etc.


The other advantage of classes is:

2) Inheritance

With classes, you can *inherit* behaviour by creating a subclass. Say, for
example, you want a type of list that is exactly the same as ordinary lists
except that every time you append a value, it prints what you appended. This
might be useful for debugging. Without inheritance, you would have to
duplicate the entire code base for list, many hundreds or thousands of lines
of code. But with inheritance, it just takes FOUR lines:

class MyList(list):
     def append(self, value):
         print("appending %s" % value)
         super(MyList, self).append(value)


This creates a new class called "MyList", which inherits from the built-in
list class; everything else is the same as list, except for the append
method, which prints the value first, then calls the built-in list.append
method.

(If the super() call looks a bit mysterious, don't worry too much about it
right now.)



So between encapsulation and inheritance, classes are a powerful tool for
programming.



-- 
Steven


More information about the Tutor mailing list