Chapter 1. Python Has Class

This chapter will read like a whirlwind tour of Python, hitting on primarily object-oriented programming and making sense of the somewhat strange-looking syntax of the Python language. Python is a tool and a language. The language includes the syntax and formatting of code according to the Python standard. The tool is a software package included with the Python installation that includes an editor. This is some pretty heavy-hitting material for a first chapter. If this is your first exposure to programming in Python, don’t let the pacing of this first chapter throw you off—we cover some important details right away, but the book does not get harder with each new chapter. Here is what you will learn:

  • How to enter Python code into the IDLE editor

  • Using the tools that come with Python

  • Reviewing the language features of Python

  • Perusing the history of programming languages

  • Speculating on the next generation programming methodology

  • Polymorphism and inheritance

  • Writing an example using multiple inheritance

Examining the Geometry Program

This chapter is a quick romp through Python’s object-oriented programming capabilities to get you up to speed on programming in Python the “OOP way” right from the beginning. If you don’t understand everything covered in this chapter all at once, don’t worry about it, because we will be revisiting all of these concepts in every chapter from here on, while creating games to learn—no, to master—the language of Python! Our first example is shown in Figure 1.1.

The Geometry Demo is a quick jaunt through Python’s object-oriented programming capabilities.

Figure 1.1. The Geometry Demo is a quick jaunt through Python’s object-oriented programming capabilities.

Getting Started with Python

Python is both a package of software tools and a language. The Python software package includes an editor called IDLE, which is short for... actually, nothing. Idle is the name of a man, not an acronym for integrated development... something, although that seems to fit. The man’s name, for those with a penchant for useless trivia, is Eric Idle, one of the founding members of Monty Python, which is where the name comes from: an homage to a British TV show. The Python language is strange too, so it is an appropriate name. Strange in a beloved way, of course! If you are completely new to Python and have not read the introductory book by Michael Dawson (Python Programming for the Absolute Beginner), then you may be pleasantly surprised to find Python is unlike any other programming language! That makes learning Python a bit of a challenge, but a rewarding one nonetheless.

Note

Getting Started with Python

Go to http://www.python.org if you want to download the latest Python package for your operating system of choice.

Python Tools

The Python package includes the Python interpreter and runtime libraries as one would expect, but it also includes several useful utilities that we will take a look at now.

Module Docs (Pydoc)

The Python package differs depending on the operating system, but most commonly the package will include Pydoc, the Python documentation tool. This tool is a small search utility that will locate items in the Python documentation, present the search results in a list, and then bring up any one item in the default web browser. In the Python program group, this utility is also called Module Docs. See Figure 1.2.

Pydoc brings up help pages in the default web browser.

Figure 1.2. Pydoc brings up help pages in the default web browser.

Python Manuals (Pyhelp)

Also found in the program menu is an option, Python Manuals, that brings up the Python documentation in a Windows help file format, shown in Figure 1.3. This version of the documentation is searchable, but may not be as fast a way to look up what you need to find.

Python documentation displayed as a Windows help file.

Figure 1.3. Python documentation displayed as a Windows help file.

Python (command line)

Python is an interpreted language, which means code is not compiled into an executable file; it is just interpreted on the fly in real time. That real time nature includes the Python command prompt, which can accept Python commands one line at a time. Of course, this is a limited way to write Python code and may be thought of as just a parser rather than “code,” so to speak. Figure 1.4 shows the command prompt.

The Python command prompt will interpret commands.

Figure 1.4. The Python command prompt will interpret commands.

IDLE (Python GUI)

IDLE is a text editor and simple development environment for Python programming. Figure 1.5 shows IDLE in action, displaying a pop-up help message for the code currently being typed in. In this case, it is the syntax for the print() function. But this is not the IDLE editor; it is just the IDLE command prompt. Yes, we can run an independent prompt like the one shown previously in Figure 1.4, or use the one built into IDLE. To begin actual editing, use the File menu and choose New Window, as shown in Figure 1.6. This creates a new source code editor window, shown in Figure 1.7.

IDLE is the text editor included with Python.

Figure 1.5. IDLE is the text editor included with Python.

Creating a new source code editor window with IDLE.

Figure 1.6. Creating a new source code editor window with IDLE.

Typing in code into the new source code window.

Figure 1.7. Typing in code into the new source code window.

Before doing anything else, you will first want to save the new source code as a file. Until you do this, you cannot have Python run (or interpret) your code. Use the File menu to save the file, then open the Run menu, and choose Run Module. You can also run the code by pressing F5. Now, an interesting thing happens when you run the program. The output goes into the main IDLE window that originally came up! See Figure 1.8. You should leave the prompt (also called the Python Shell) open when editing files because it is the main output window for running programs, even when using a graphical window with Pygame (more on that in the next chapter).

Typing code into the new source code window.

Figure 1.8. Typing code into the new source code window.

Python Language

Python, the language, is one very strange-looking programming language that appears to have been designed by a travelling drama troupe with a penchant for obscure Isles humor of the sort that Americans find insufferable and indecipherable. Of course, that is only an emotionally charged, higher education–borne opinion, so one is advised to take it with a grain of salt. Python is also powerful and versatile, and will surprise you with its capabilities—as soon as you become familiar with it.

It’s really surprisingly difficult to compare Python to a language like C++, for there are no opening and closing braces or recognizable function names. The constructor for a Python class is ... well, I don’t want to frighten you right off the bat, and have you running back to, say, BASIC, but a constructor is rather obtuse looking. Not that there’s anything whatsoever wrong with BASIC! I happen to enjoy an especially awesome tool called QB64 (www.qb64.net), which is featured in another book entitled Video Game Programming for Kids. IDLE is a very useful text editor included with the Python package, and we will be using it in this book.

Note

Python Language

There is an online reference manual for Python located at: http://docs.python.org/reference.

Objects in Python

Python is an object-oriented programming language, which means it supports at least some object-oriented programming concepts. We will spend some time going over those concepts now because this is an effective way to write code. Object-oriented programming (OOP) is a methodology. That is, a way of doing things. There have been several large, “umbrella” methodologies in computer science—that is, methodologies that defined the functionality of programming languages. A methodology is important for the industry in order to make our skills transferrable. If every company used their own methodology, then the skills gained while working for that company would be useless at a different organization. Software engineering is a challenging field, and education is costly, so methodologies are good for everyone involved—skilled developers, employers, and educators who teach the concepts.

What Came Before?

If you have a natural curiosity, which is common among talented programmers, then you may be wondering what type of programming came before the object-oriented paradigm. Let’s peruse the subject a bit, if only to illustrate why this is so important to go over up front before we have even really started using Python. Let’s peruse where we have come from in order to appreciate where we are today in terms of programming technology.

Structured Programming

Before OOP, the methodology was called procedural or structured programming, which implies that procedures and structures were used, and this is the case. Procedures are often called functions, and we still use them today. Yes, even in an OOP program there will be standalone functions, such as main(). A function contained inside an object is called a method, and this term has replaced the term function when it is part of an object. But, functions can still exist outside of an object, and that is a carryover from the previous “age” (methodology). Structures are complex user-defined types (UDTs) that can contain many variables organized together. The most popular structured language was C. But this was a long and successful methodology that some still adhere to today. The time frame for the structured movement was the 1980s and 1990s, but of course there was quite a bit of overlap in both directions. In the electronics industry, many software development kits (SDKs) are still developed in a structured manner, with libraries of functions supplied to control an electronic device (such as a video card or embedded system). It might be argued that the development of the C language (at right around 1970) ushered in structured programming in a major way. The C language was used to create the UNIX operating system.

Here is a quick example of a structured program in Python.

# Structured program

# Function definition
def PrintName(name):
    print("The name is " + name + ".")

# Start of program
PrintName("Jane Doe")

The program produces this output:

The name is Jane Doe.

Note

Structured Programming

A comment line in Python begins with the pound character (#).

The function definition begins with the word def, followed by the function name, parameters, and a colon. There are no code block characters in Python, like the opening brace ({) and closing brace (}) in C++. In Python, the end of the function is undefined, assumed to end before the next non-indented line. Let’s try a little experiment to test the behavior of Python. Here’s our example again, without any comment lines. What do you think it will print out?

def PrintName(name):
    print("The name is " + name + ".")
print("END")
PrintName("Jane Doe")

The output is:

END
The name is Jane Doe.

This is a surprise to most Python beginners. What’s happening is the print("END") line is indented on the left, so it became the first line of the program, followed by PrintName("Jane Doe"), the second line. The function definition is not considered part of the main program, and is only run when the function is called. What happens if we move the function definition below the main program like this?

PrintName("Jane Doe")

def PrintName(name):
    print("The name is " + name + ".")

That code actually produces a syntax error because the PrintName function could not be found. This tells us that Python must parse functions before they are called. In other words, function defs must be “above” code where the function is called.

Traceback (most recent call last):
  File "FunctionDemo.py", line 4, in <module>
    PrintName("Jane Doe")
NameError: name 'PrintName' is not defined

Note

Structured Programming

When saving a source code file with IDLE, be sure to include the extension .PY, as IDLE does not automatically append the extension.

Sequential Programming

Structured programming evolved from the earlier sequential programming methodology. This is not a formal textbook description but more of a descriptive one. Sequential programs required line numbers before each line of code. While it was possible to jump (with goto or gosub commands) to another line of the program, and that was an early evolution in the direction of structure, sequential programs had the tendency to get stuck with a certain level of complexity, beyond which the code became indecipherable, or impossible to change. The problem at the time was called “spaghetti code” because of the way the “flow” of the program seemed to go every which direction. The two most popular sequential languages were BASIC and FORTRAN, and the heyday for these languages was the 1970s and 1980s. As developers grew tired of maintaining spaghetti code, a paradigm shift was needed, and structure was ushered in with the introduction of new structured languages like Pascal and C.

10 print "I am freaking out!"
20 goto 10

Note

Sequential Programming

Do you actually find this sequential code kind of interesting? I do! It takes me back a few years. There’s a great (and free) compiler called QB64 at www.qb64.net, that supports all of the old flavors of BASIC, QBASIC, and QuickBasic (which is structured, not sequential). In addition, QB64 supports OpenGL, so there’s potential for advanced graphics and gameplay as well as support for the old-school variations of BASIC.

Mnemonic Programming

Prior to sequential programming, developers wrote code much closer to the level of the computer hardware, using assembly language. An “assembler” program was like a compiler, but it would convert mnemonic (“nee-monic”) instructions directly into machine code in an object or binary file, ready to be run by the processor one byte at a time. One assembly mnemonic instruction correlates directly to one machine instruction that the processor understands. This is like speaking the machine’s own language and is very challenging! In the old days of MS-DOS, these assembly instructions would change the video mode to a graphics mode with 320x200 resolution and 256 (8-bit) color, which was great for an IBM PC game back in the early 1990s because it was fast. Remember, in this time period, there were no video cards like we have today, just “video out” built into the ROM BIOS and whatever modes were supported by an operating system. This was called the infamous “VGA mode 13h” that all game developers loved at the time.

mov ax, 13h
int 10h

Note

Mnemonic Programming

Here is an interesting historical site dedicated to programming VGA mode 13h: http://www.delorie.com/djgpp/doc/ug/graphics/vga.html.

“AX” is a 16-bit processor register, an actual physical circuit on the processor that was treated like a general-purpose “variable” of sorts, to use a familiar term without the language of electronics engineering. There were three other general-purpose registers: BX, CX, and DX. They were themselves upgrades from the earlier 8-bit Intel processors, which had registers called A, B, C, and D. When 16-bit was developed, these registers were expanded into AL/AH, BL/BH, CL/CH, and DL/DH, which were two 8-bit parts of each 16-bit register. It’s not as complicated as it might sound at first. Put a value into one or more of these variable registers, then “launch” a procedure by calling an interrupt. In the case of the VGA mode change, the interrupt was 10h.

What’s Coming Next?

Now that we have taken a brief look at the programming methodologies of the past that led up to this point, as a means of understanding and appreciating the tools and languages we have today, let’s talk about the current state of the art and what’s coming. Today, object-oriented programming is still the main methodology used by most professional programmers. It is the basis for popular industry-leading tools like Visual Studio and the .NET Framework from Microsoft. The major compiled OOP languages used in business and science today are C++, C# (“see-sharp”), BASIC (the modern variation known as Visual Basic), and Java. There are others, but these are the big league players.

Python and LUA are scripting languages. In comparison to compiled languages like C++, Python and LUA are handled quite differently—interpreted rather than compiled. When you run a Python program (a file with an extension of .PY), it is not compiled, it is run. You could insert syntax errors into a function in Python and unless that function is called, Python will never complain about the errors!

# Funny syntax error example

# Bad function!
def ErrorProne():

    printgobblegobble("Hello there!")

print("See, nothing bad happened. You worry too much!")

There is no function called printgobblegobble() in Python or in this program, so that should have generated an error! Here is the output:

See, nothing bad happened. You worry too much!

But, if you add a call to the ErrorProne() function, this will be the output:

Traceback (most recent call last):
  File "ErrorProne.py", line 9, in <module>
    ErrorProne()
  File "ErrorProne.py", line 5, in ErrorProne
    printgobblegobble("Hello there!")
NameError: global name 'printgobblegobble' is not defined

Now, there are limits to this apparent ignorance on the part of Python. If you blatantly define a variable the wrong way, it will generate an error first before running. There’s another weird thing you can do in Python to totally screw things up: using reserved words as variables. Behold:

print = 10
print(print)

The first line works just fine, but the second line produces this error:

Traceback (most recent call last):
  File "ErrorProne.py", line 8, in <module>
    print(print)
TypeError: 'int' object is not callable

What this error means is, print has become a variable, an integer to be exact, set to the value of 10. Then we try to call the old print() function, and Python doesn’t get it. Because the old print() function has been bypassed. Now, this strange behavior does not apply to reserved words in the Python language, like while, for, if, and so on, only to functions. I think you will be surprised to find a great amount of flexibility in Python as a scripting language.

A traditional compiler, like GCC or Visual C++, would pitch a fit before even thinking about running such code! But then, these are compilers. They parse the flow of a program completely before converting it into object code. And therein lies the disadvantage: a compiler cannot work with unknowns, only that which is known, while a scripting language can handle the unknown very well!

The next methodology will evolve from OOP the way sequential evolved into structured, and structured into OOP, with telltale signs of the change showing up in the current methodology before the paradigm change happens. The change happening today to OOP might be called adaptive programming. In the fast-paced world of today, no one sits down at their computer with a 200-page manual for WordPerfect or Lotus 1-2-3 like we did in the old days of computing. There are still people who think “read the manual!” is a reasonable answer to technical questions, but today it’s rare if a product even comes with a semblance of a manual. Today, systems must be interactive and adaptable. The next evolution beyond OOP could very well be entity Oriented Programming or EOP.

Instead of writing code with objects containing properties (variables) and methods (functions), imagine using entities—self-contained objects that work together with simple rules to solve complex problems. That seems to be the direction of A.I. research, and could very well be adapted into existing OOP languages today. In fact, there are early signs of this already happening. Ever heard of web services? A web service is a self-contained object that resides online, and can be used by a program to perform unique services that it did not know how to do. Those web services might just ask for a parameter for an inventory database and return a list of items that match the query. This form of program interaction sure beats writing SQL (structured query language)—the language of relational databases! What about taking it to the next level? Instead of tapping into a known service, what about querying for a service online using some sort of repository or search engine?

As another possible example, imagine an online storehouse of game entities that can be used in a game (most likely pioneered by indie developers or open source teams), where the entity will come with its own art assets (2D sprites, 3D meshes, textures, audio clips, etc.) and it’s own behaviors (such as a Python script). An existing game engine that requires assets to be in a certain format could use this sort of EOP concept to extend gameplay. Imagine you are playing a game, some sort of world building game like Minecraft (www.minecraft.net), and you imagine some new character in the game. So, you query for it, “I need a short wooden chair.” After a slight delay for the query to be sent out, a short wooden chair appears in front of you in the game. Assuming there is an online repository of game assets for an engine like Minecraft, it’s not beyond reason to imagine this sort of development to occur.

OOP: The Python Way

We have done enough historical analysis and speculation to trigger some imaginative thinking, so let’s learn about something concrete and practical now—the current OOP methodology as it is implemented in Python. Or, in other words, creating objects in Python! Python does support some OOP features, but not all to the degree of a highly specific language like C++. Let’s get the terminology straight first, before we get started. A class is a blueprint for an object. A class cannot do anything, because it is a blueprint. An object does not exist until it is created at runtime. So, when we are writing the code, it is a class definition, not an object. It is only truly an object when it is created at runtime from the blueprint of a class. A class function is called a method. A class variable is usually accessed as a property (a sort of method for getting or setting the value of a variable). When an object is created, the class is instantiated into the object.

Let’s learn about the specifics of Python’s OOP features. Here is an example:

class Bug(object):
    legs = 0
    distance = 0

    def __init__(self, name, legs):
        self.name = name
        self.legs = legs

    def Walk(self):
        self.distance += 1

    def ToString(self):
        return self.name + " has " + str(self.legs) + " legs" + 
            " and taken " + str(self.distance) + " steps."

Every definition must be followed by a colon at the end of the line. The key word self describes the current class, and is equivalent to this in C++. All class variables must be prefixed with “self.” in order to be recognized as members of the class; otherwise, they are treated as local.

The def __init__(self) line begins the class constructor—the first method that runs when the class is instantiated. Class variables can be declared and initialized outside of the constructor when they are declared.

Polymorphism

The term polymorph means “many forms” or “many shapes”, so polymorphism is the ability to take many forms or shapes. In the context of a class, this means we can use methods with many shapes—that is, many different sets of parameters. In Python, we can use optional parameters to make a method more versatile. The constructor of our new Bug class can be transformed with the use of optional parameters like so:

    def __init__(self, name="Bug", legs=6):
        self.name = name
        self.legs = legs

Likewise, the Walk() method can be upgraded to support an optional parameter:

    def Walk(self,distance=1):
        self.distance += distance

Data Hiding (Encapsulation)

Python does not allow variables or methods to be declared as private or protected, as the scope of all things is public in Python. But, if you want to write code that makes it look like data hiding is working, that is definitely doable. For instance, this code might be used to access or change the distance variable (which we would assume is private, even though it isn’t):

    def GetDistance(self):
       return p_distance

    def SetDistance(self, value):
        p_distance = value

From a data hiding point of view, you could rename distance to p_distance (making it appear to be a private variable), and then access it using these two methods. That is, if data hiding is important in your program.

Inheritance

Python supports inheritance of base classes. When a class is defined, the base class is included in parentheses:

class Car(Vehicle):

In addition, Python supports multiple inheritance; that is, more than one parent or base class can be inherited from in a child class. For example:

class Car(Body,Engine,Suspension,Interior):

As long as the variables and methods in each parent class do not conflict with each other, the new child class can access them all without incident. But, if there are any conflicts, the conflicted variable or method is used from the parent that comes first in the inheritance ordering.

When a Python class inherits from a base class, all of the variables and methods of the parent are available. Variables can be used, and methods can be overridden. When calling the constructor or any method of a base class, we can use super() to refer to the base:

return super().ToString()

But when multiple inheritance is involved, the name of the parent class must be used when both share the same variable or method name, to resolve the confusion.

Single Inheritance

Let’s look at an example of single-parent inheritance first. Here is a Point class and a Circle class that inherits from it:

class Point():
    x = 0.0
    y = 0.0

    def __init__(self, x, y):
        self.x = x
        self.y = y
        print("Point constructor")

    def ToString(self):
        return "{X:" + str(self.x) + ",Y:" + str(self.y) + "}"

class Circle(Point):
    radius = 0.0

    def __init__(self, x, y, radius):
        super().__init__(x,y)
        self.radius = radius
        print("Circle constructor")

    def ToString(self):
        return super().ToString() + 
               ",{RADIUS=" + str(self.radius) + "}"

We can test these classes simply enough:

p = Point(10,20)
print(p.ToString())

c = Circle(100,100,50)
print(c.ToString())

That produces this output:

Point constructor
{X:10,Y:20}

Point constructor
Circle constructor
{X:100,Y:100},{RADIUS=50}

We can see that Point is simple enough in function, but Circle calls the Point constructor before its own, and then uses the complex ToString() call from Point and adds its own new radius property to the mix. This is really helpful to see which is why all of our classes have a ToString() method.

Note

Single Inheritance

Multiple inheritance is a quagmire! I recommend avoiding it when possible and just keeping classes simple and straightforward, with perhaps one level of inheritance at most. Give your classes a lot of functionality rather than dividing them up across several classes, for best results.

Now, when the Circle class is created, the constructor is called with the three parameters passed to it (100,100,50). Note that the parent (Point) constructor is called to handle the x and y parameters, while the radius parameter is handled inside Circle:

    def __init__(self, x, y, radius):
        super().__init__(x,y)
        self.radius = radius

The call to super() invokes the constructor of the Point class, which is the parent or base class of Circle. This works marvelously when single inheritance is used!

Multiple Inheritance

I would be remiss by not at least showing you how multiple inheritance works, even if it is a quagmire! We essentially cannot use super() to invoke anything in the parent class when using multiple inheritance, unless the variables and methods of each parent class are unique. Here is another pair of classes that build on the previous two already shown. Remember when I warned you that Python was a strange-looking language? We are now seeing that here! Try to remember that Python is a script language, not a compiled language. Python code is interpreted while it runs.

class Size():
    width = 0.0
    height = 0.0

    def __init__(self,width,height):
        self.width = width
        self.height = height
        print("Size constructor")

    def ToString(self):
        return "{WIDTH=" + str(self.width) + 
               ",HEIGHT=" + str(self.height) + "}"

class Rectangle(Point,Size):
    def __init__(self, x, y, width, height):
        Point.__init__(self,x,y)
        Size.__init__(self,width,height)
        print("Rectangle constructor")

    def ToString(self):
        return Point.ToString(self) + "," + Size.ToString(self)

The Size class is a new helper class, while Rectangle is our real focus for the example. Here, we are inheriting from both Point and Size:

class Rectangle(Point,Size):

Point was defined earlier, while Size was defined just above. Now, we could just begin using Point.x, Point.y, Size.width, and Size.height, as well as the ToString() methods in each. Python would not complain. But, the idea is to auto-initialize parent classes by calling their constructors. Otherwise, we are losing all benefit of OOP and might as well just write structured code! So, the Rectangle constructor must call each parent constructor by name:

    def __init__(self, x, y, width, height):
        Point.__init__(self,x,y)
        Size.__init__(self,width,height)

Note that x and y are passed to Point.__init__(), while width and height are passed to Size.__init__(). This properly initializes those variables within their respective classes. Of course we could have just defined x, y, width, and height right inside Rectangle, but this is a demonstration! In general, I would recommend doing just that to simplify the code! There is absolutely no reason to use inheritance in this manner in a real-life program. It is purely for illustration. Testing out our new Size and Rectangle classes:

s = Size(80,70)
print(s.ToString())

r = Rectangle(200,250,40,50)
print(r.ToString())

Produces this output:

Size constructor
{WIDTH=80,HEIGHT=70}

Point constructor
Size constructor
Rectangle constructor
{X:200,Y:250},{WIDTH=40,HEIGHT=50}

Now this is really quite interesting! Size is simple enough to follow, but look at the output for Rectangle! We have a call to the Point constructor and Size constructor, exactly as planned! Furthermore, the ToString() method combines the output of Point.ToString() and Size.ToString() effectively.

Summary

This chapter was very fast paced for the first chapter on Python programming! Is your hair messy from going so fast? Don’t worry, we’re going to put code like this to use in a practical way, by actually drawing points, circles, and rectangles, among other things! We will also create a sprite class for drawing game characters on the screen with animation as a learning tool for Python! The good news is, this was probably the hardest chapter because it was your first exposure to not only the strange-looking Python syntax, but also to object-oriented programming in all likelihood! As you will find in later chapters, the straightforward approach to learning a programming language is usually the best way. I hope you are ready to go, because in the very next chapter we’ll begin learning Pygame!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.197.95