307 lines
12 KiB
HTML
307 lines
12 KiB
HTML
<!--startcut ==============================================-->
|
|
<!-- *** BEGIN HTML header *** -->
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
|
|
<HTML><HEAD>
|
|
<title>An Introduction to Object-Oriented Programming in Python LG #56</title>
|
|
</HEAD>
|
|
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#0000AF"
|
|
ALINK="#FF0000">
|
|
<!-- *** END HTML header *** -->
|
|
|
|
<CENTER>
|
|
<A HREF="http://www.linuxgazette.com/">
|
|
<H1><IMG ALT="LINUX GAZETTE" SRC="../gx/lglogo.jpg"
|
|
WIDTH="600" HEIGHT="124" border="0"></H1></A>
|
|
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="nielsen.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue56/orr.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="skjoldebrand.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
<P>
|
|
</CENTER>
|
|
|
|
<!--endcut ============================================================-->
|
|
|
|
<H4 ALIGN="center">
|
|
"Linux Gazette...<I>making Linux just a little more fun!</I>"
|
|
</H4>
|
|
|
|
<P> <HR> <P>
|
|
<!--===================================================================-->
|
|
|
|
<center>
|
|
<H1><font color="maroon">An Introduction to Object-Oriented Programming in Python</font></H1>
|
|
<H4>By <a href="mailto:mso@mso.oz.net">Michael Orr</a></H4>
|
|
</center>
|
|
<P> <HR> <P>
|
|
|
|
<!-- END header -->
|
|
|
|
|
|
|
|
|
|
<P> Somebody asked Michael Williams if he could do Python and Java versions of
|
|
his article
|
|
<A HREF="../issue55/williams.html">An Introduction to Object-Oriented
|
|
Programming in C++</A>. Here's a Python version of the code. I'll comment
|
|
on the differences between C++ and Python. Perhaps somebody else can
|
|
write a Java version?
|
|
|
|
<P> I am assuming you know the basics of Python. If not, see the
|
|
excellent
|
|
<A HREF="http://www.python.org/doc/current/tut/tut.html">Tutorial</A>
|
|
and the other documentation at
|
|
<A HREF="http://www.python.org/doc/">http://www.python.org/doc/</A>.
|
|
|
|
<H2>Houses and more houses</H2>
|
|
|
|
<P> To represent Michael's house (in section <STRONG>Classy!</STRONG> in the
|
|
C++ article), we can use the following code:
|
|
(<A HREF="misc/orr/house.py.txt">text version</A>)
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
#! /usr/bin/python
|
|
"""house.py -- A house program.
|
|
This is a documentation string surrounded by triple quotes.
|
|
"""
|
|
|
|
class House:
|
|
pass
|
|
|
|
my_house = House()
|
|
my_house.number = 40
|
|
my_house.rooms = 8
|
|
my_house.garden = 1
|
|
|
|
print "My house is number", my_house.number
|
|
print "It has", my_house.rooms, "rooms"
|
|
if my_house.garden:
|
|
garden_text = "has"
|
|
else:
|
|
garden_text = "does not have"
|
|
print "It", garden_text, "a garden"
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
If we run it, it prints:
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
My house is number 40
|
|
It has 8 rooms
|
|
It has a garden
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<P> What does this program do? First, we define what a generic house is in the
|
|
<CODE>class</CODE> block. <CODE>pass</CODE> means "do nothing" and is required
|
|
if the block would otherwise be empty. Then we create an instance (that is, a
|
|
particular house) by calling the class name as if it were a function. The
|
|
house is then stored in the variable <CODE>my_house</CODE>.
|
|
|
|
<P> This house initially has no attributes--if we were to query
|
|
<CODE>my_house.number</CODE> before setting it, we'd get an AttributeError.
|
|
The next three lines set <EM>and create</EM> the attributes. This is a
|
|
difference between the languages: Java instances start out with certain
|
|
attributes which can never change (although their values can change), but
|
|
Python instances start out with no attributes, and you can add or delete
|
|
attributes (or change their type) later. This allows Python to be more flexible
|
|
in certain dynamic situations.
|
|
|
|
<P> We can initialize the instance at creation time by including a special
|
|
<CODE>__init__</CODE> method. (A method is a function which "belongs" to a
|
|
class.) This program:
|
|
(<A HREF="misc/orr/house2.py.txt">text version</A>)
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
#! /usr/bin/python
|
|
"""house2.py -- Another house.
|
|
"""
|
|
|
|
class House:
|
|
def __init__(self, number, rooms, garden):
|
|
self.number = number
|
|
self.rooms = rooms
|
|
self.garden = garden
|
|
|
|
my_house = House(20, 1, 0)
|
|
|
|
print "My house is number", my_house.number
|
|
print "It has", my_house.rooms, "rooms"
|
|
if my_house.garden:
|
|
garden_text = "has"
|
|
else:
|
|
garden_text = "does not have"
|
|
print "It", garden_text, "a garden"
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
prints:
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
My house is number 20
|
|
It has 1 rooms
|
|
It does not have a garden
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
Because the class has an <CODE>__init__</CODE> method, it's automatically
|
|
called when an instance is created. The arguments to <CODE>House</CODE> are
|
|
really the arguments to <CODE>__init__</CODE>. Although most programs don't,
|
|
you can also call <CODE>__init__</CODE> yourself as many times as you want:
|
|
<CODE>my_house.__init__(55, 14, 1)</CODE>. This tells the object to
|
|
"reinitialize itself".
|
|
|
|
<P> Note that <CODE>__init__</CODE> is defined with an extra first argument,
|
|
<CODE>self</CODE>. But we <EM>don't</EM> specify
|
|
<CODE>self</CODE> when we call the method. All Python methods work like
|
|
this.
|
|
<CODE>self</CODE> is in fact the instance itself, and Python supplies it
|
|
behind the scenes. You need <CODE>self</CODE> because it's the only way the
|
|
method can access the instance's attributes and other methods. Inside the
|
|
method,
|
|
<CODE>self.rooms</CODE> means the instance's attribute <CODE>rooms</CODE>, but
|
|
<CODE>rooms</CODE> means the
|
|
<STRONG>local variable</STRONG> <CODE>rooms</CODE>.
|
|
Local variables, of course, vanish when the method ends. Python's use of
|
|
<CODE>self</CODE> is parallelled in Perl and other OO languages as well.
|
|
|
|
<P> Michael didn't tell you, but C++ has a <CODE>this</CODE> pointer which
|
|
works like Python's <CODE>self</CODE>. However, in C++ you don't have to type
|
|
<CODE>this->house</CODE> if there is no local variable <CODE>house</CODE>,
|
|
and you never type <CODE>this</CODE> on a method definition line. In other
|
|
words, C++ (and Java) do the same thing as Python and Perl; they just hide it
|
|
from the programmer.
|
|
|
|
<P> In fact, <CODE>self</CODE> in Python is just a conventional name. You can
|
|
call it <CODE>this</CODE> or <CODE>me</CODE> instead if you like. I actually
|
|
like <CODE>me</CODE> better. However, I stick with <CODE>self</CODE> so that
|
|
if somebody else has to maintain my work later, it will be easier for them to
|
|
read. In contrast, C++'s variable <CODE>this</CODE> is magic and cannot be
|
|
renamed.
|
|
|
|
<P> In the C++ program, <CODE>garden</CODE> is a boolean attribute. Python
|
|
doesn't have boolean attributes, so we use an integer instead. The expression
|
|
<CODE>my_house.garden</CODE> is true if the attribute is 1 (or any
|
|
non-zero, non-empty value).
|
|
|
|
<H2>Don't be square</H2>
|
|
|
|
<P> This section corresponds to the "Member Functions" section in Williams'
|
|
article. I prefer the term "method" over "member function", as Pythoneers
|
|
usually do. Michael's <CODE>square.c</CODE> program would look like this:
|
|
(<A HREF="misc/orr/square.py.txt">text version</A>)
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
#! /usr/bin/python
|
|
"""square.py -- Make some noise about a square.
|
|
"""
|
|
|
|
class Square:
|
|
def __init__(self, length, width):
|
|
self.length = length
|
|
self.width = width
|
|
|
|
def area(self):
|
|
return self.length * self.width
|
|
|
|
my_square = Square(5, 2)
|
|
print my_square.area()
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
prints
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
10
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<P> <CODE>area</CODE> should be self explanatory because it works exactly like
|
|
<CODE>__init__</CODE> above. To reiterate, all the <CODE>self</CODE>s in
|
|
square.py are required. I have chosen to give Square an <CODE>__init__</CODE>
|
|
method rather than setting the attributes later, because that's what most
|
|
Python programmers would do.
|
|
|
|
<H2>Function definitions outside the class definition</H2>
|
|
|
|
<P> Nothing to say here. Python does not allow methods to be defined outside
|
|
the class. Of course, this doesn't apply to ordinary (non-class) functions.
|
|
|
|
<H2>Public or private?</H2>
|
|
|
|
<P> Not much to say here either. All Python attributes and methods are public.
|
|
You <EM>can</EM> emulate private attributes and methods via the
|
|
<A HREF="http://www.python.org/doc/current/tut/node11.html#SECTION0011600000000000000000">double-underscore hack</A>, but most Python programmers don't.
|
|
Instead, they count on the programmer not to abuse the class's API.
|
|
|
|
<H2>Class constructors</H2>
|
|
|
|
The <CODE>__init__</CODE> method <EM>is</EM> the constructor.
|
|
|
|
<H2>Arrays and classes</H2>
|
|
|
|
Williams' array example can't be coded literally because of differences between
|
|
the languages, but one equivalent is:
|
|
(<A HREF="misc/orr/person.py.txt">text version</A>)
|
|
|
|
<BLOCKQUOTE><PRE>
|
|
#! /usr/bin/python
|
|
"""person.py -- A person example.
|
|
"""
|
|
class Person:
|
|
def __init__(self, age, house_number):
|
|
self.age = age
|
|
self.house_number = house_number
|
|
|
|
alex = []
|
|
for i in range(5):
|
|
obj = Person(i, i)
|
|
alex.append(obj)
|
|
|
|
print "Alex[3] age is", alex[3].age
|
|
print
|
|
|
|
for alexsub in alex:
|
|
print "Age is", alexsub.age
|
|
print "House number is", alexsub.house_number
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
This prints:
|
|
<BLOCKQUOTE><PRE>
|
|
Alex[3] age is 3
|
|
|
|
Age is 0
|
|
House number is 0
|
|
Age is 1
|
|
House number is 1
|
|
Age is 2
|
|
House number is 2
|
|
Age is 3
|
|
House number is 3
|
|
Age is 4
|
|
House number is 4
|
|
</PRE></BLOCKQUOTE>
|
|
|
|
<P> Python has no equivalent to <CODE>person alex[5]</CODE> in the C++
|
|
program, which creates an array of five empty instances all at once. Instead,
|
|
we create an empty list and then use a <CODE>for</CODE> loop (which sets
|
|
<CODE>i</CODE> to 0, 1, 2, 3 and 4 respectively) to populate it. The example
|
|
shows a loop subscripting a list by index number, another loop which gets each
|
|
element in the list directly, and a <CODE>print</CODE> statement which access
|
|
an element by index number.
|
|
|
|
|
|
|
|
|
|
|
|
<!-- *** BEGIN copyright *** -->
|
|
<P> <hr> <!-- P -->
|
|
<H5 ALIGN=center>
|
|
|
|
Copyright © 2000, Michael Orr<BR>
|
|
Published in Issue 56 of <i>Linux Gazette</i>, August 2000</H5>
|
|
<!-- *** END copyright *** -->
|
|
|
|
<!--startcut ==========================================================-->
|
|
<HR><P>
|
|
<CENTER>
|
|
<!-- *** BEGIN navbar *** -->
|
|
<IMG ALT="" SRC="../gx/navbar/left.jpg" WIDTH="14" HEIGHT="45" BORDER="0" ALIGN="bottom"><A HREF="nielsen.html"><IMG ALT="[ Prev ]" SRC="../gx/navbar/prev.jpg" WIDTH="16" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="index.html"><IMG ALT="[ Table of Contents ]" SRC="../gx/navbar/toc.jpg" WIDTH="220" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../index.html"><IMG ALT="[ Front Page ]" SRC="../gx/navbar/frontpage.jpg" WIDTH="137" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="http://www.linuxgazette.com/cgi-bin/talkback/all.py?site=LG&article=http://www.linuxgazette.com/issue56/orr.html"><IMG ALT="[ Talkback ]" SRC="../gx/navbar/talkback.jpg" WIDTH="121" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><A HREF="../faq/index.html"><IMG ALT="[ FAQ ]" SRC="./../gx/navbar/faq.jpg"WIDTH="62" HEIGHT="45" BORDER="0" ALIGN="bottom"></A><A HREF="skjoldebrand.html"><IMG ALT="[ Next ]" SRC="../gx/navbar/next.jpg" WIDTH="15" HEIGHT="45" BORDER="0" ALIGN="bottom" ></A><IMG ALT="" SRC="../gx/navbar/right.jpg" WIDTH="15" HEIGHT="45" ALIGN="bottom">
|
|
<!-- *** END navbar *** -->
|
|
</CENTER>
|
|
</BODY></HTML>
|
|
<!--endcut ============================================================-->
|