Programming objects - Coding for Beginners in Easy Steps: Basic Programming for All Ages (2015)

Coding for Beginners in Easy Steps: Basic Programming for All Ages (2015)

10. Programming objects

This chapter demonstrates how to code virtual objects into your programs.

Defining classes

Copying instances

Addressing properties

Deriving classes

Overriding methods

Applying sense

Summary

Defining classes

The real-world objects that surround us each have attributes and behaviors we can describe. For example, a car might be described with a color attribute “red” and an “acceleration” behavior. Programming objects are like virtual representations of real-world objects that describe attributes and behaviors in a “class” structure.

A “class” is a specified prototype describing a set of properties that characterize an object. Each class has a data structure that can contain both functions and variables to characterize the object. The properties of a class are referred to as its data “members”. Class function members are known as its “methods”, and class variable members (declared within a class structure but outside any method definitions) are known as its “attributes”. Class members can be referenced throughout a program using dot notation, suffixing the member name after the class name, with syntax of class-name.method-name() or class-name.attribute-name.

image

A class declaration begins with the class keyword, followed by a programmer-specified name (adhering to the usual Python naming conventions but beginning in uppercase) then a : colon. Next come indented statements, optionally specifying a class document string, class variable attribute declarations, and class method definitions – so the class block syntax looks like this:

class ClassName :

‘‘‘ class-documentation-string ‘‘‘

class-variable-declarations

class-method-definitions

The class declaration, which specifies its attributes and methods, is a blueprint from which working copies (“instances”) can be made. All variables declared within method definitions are known as “instance” variables and are only available locally within the method in which they are declared – they cannot be directly referenced outside the class structure.

image

It is conventional to begin class names with an uppercase character and object names with lowercase.

Typically, instance variables contain data passed by the caller when an instance copy of the class is created. As this data is only available locally for internal use it is effectively hidden from the rest of the program. This technique of data “encapsulation” ensures that data is securely stored within the class structure and is the first principle of Object Oriented Programming (OOP).

All properties of a class are referenced internally by the dot notation prefix self – so an attribute named “sound” is self.sound. Additionally, all method definitions in a class must have self as their first parameter – so a method named “talk” is talk( self ).

When a class instance is created, a special __init__( self ) method is automatically called. Subsequent parameters can be added in its parentheses if values are to be passed to initialize its attributes.

A complete Python class declaration could look like this example:

class Critter :

‘‘‘ A base class for all critter properties. ‘‘‘

count = 0

def __init__( self , chat ) :

self.sound = chat

Critter.count += 1

def talk( self ) :

return self.sound

image

The class documentation string can be accessed via the special__doc__docstring attribute with Classname.__doc__ .

It is useful to examine the class components of this example:

•The variable count is a class variable whose integer value gets shared among all instances of this class – this value can be referenced as Critter.count from inside or outside the class

•The first method __init__() is the initialization method that is automatically called when an instance of the class is created

•The __init__() method in this case initializes an instance variable sound, with a value passed from the chat parameter, and increments the value of the count class variable whenever an instance of this class is created

•The second method talk() is declared like a regular function except the first parameter is self which is automatically incorporated – no value needs to be passed from the caller

•The talk() method in this case simply returns the value encapsulated in the sound instance variable

image

While a program class cannot perfectly emulate a real-world object, the aim is to encapsulate all relevant attributes and actions.

Copying instances

An “instance” of a class object is simply a copy of the prototype created by calling that class name’s constructor and specifying the required number of parameters within its parentheses. The call’s arguments must match those specified by the __init__() method definition – other than a value for the internal self parameter.

The class instance object returned by the constructor is assigned to a variable using the syntax instance-name = ClassName( args ).

Dot notation can be used to reference the methods and class variable attributes of an instance object by suffixing their name as instance-name.method-name() or instance-name.attribute-name.

image

A constructor creates a class instance using the class name followed by parentheses containing any required parameters.

Typically, a base class can be defined as a Python module file so it can be imported into other scripts where instance objects can be easily created from the “master” class prototype.

image

Bird.py

imageStart a new class file by declaring a new class with a descriptive document string

class Bird :

‘‘’A base class to define bird properties.’’’

imageNext, add an indented statement to declare and initialize a class variable attribute with an integer zero value

count = 0

imageNow, define the intializer class method to initialize an instance variable and to increment the class variable

def __init__( self , chat ) :

self.sound = chat

Bird.count += 1

imageFinally, add a class method to return the value of the instance variable when called – then save this class file

def talk( self ) :

return self.sound

image

You must not pass an argument value for the self parameter as this is automatically incorporated by Python.

image

instance.py

imageStart a program by making features of the class file available then display its document string

from Bird import *

print( ‘\nClass Instances Of:\n’ , Bird.__doc__ )

imageNext, add a statement to create an instance of the class and pass a string argument value to its instance variable

polly = Bird( ‘Squawk, squawk!’ )

imageNow, display this instance variable value and call the class method to display the common class variable value

print( ‘\nNumber Of Birds:’ , polly.count )

print( ‘Polly Says:’ , polly.talk() )

image

Bird instance – polly

imageCreate a second instance of the class passing a different string argument value to its instance variable

harry = Bird( ‘Tweet, tweet!’ )

imageFinally, display this instance variable value and call the class method to display the common class variable value

print( ‘\nNumber Of Birds:’ , harry.count )

print( ‘Harry Says:’ , harry.talk() )

image

Bird instance – harry

imageSave both files then run the program – to see two instances of the Bird class get created

image

image

The class variable count can also be referenced with Bird.count but the encapsulated instance variable sound can only be accessed by calling an instance’s talk() method.

Addressing properties

An attribute of a class instance can be added, modified, or removed at any time using dot notation to address the attribute. Making a statement that assigns a value to an attribute will update the value contained within an existing attribute or create a new attribute of the specified name containing the assigned value:

instance-name.attribute-name = value

del instance-name.attribute-name

Alternatively, you can use the following Python built-in functions to add, modify, or remove an instance variable:

getattr( instance-name , ‘attribute-name‘ ) – return the attribute value of the class instance

hasattr( instance-name , ‘attribute-name‘ ) – return True if the attribute value exists in the instance, otherwise return False

setattr( instance-name , ‘attribute-name‘ , value ) – update the existing attribute value or create a new attribute in the instance

delattr( instance-name , ‘attribute-name‘ ) – remove the attribute from the instance

image

The attribute name specified to these built-in functions must be enclosed within quotes.

The name of attributes automatically supplied by Python always begin with an underscore character to notionally indicate “privacy” – so these should not be modified, or removed. You can add your own attributes named in this way to indicate privacy if you wish, but in reality these can be modified like any other attribute.

image

address.py

imageStart a new program by making features of the Bird class available that was created here

from Bird import *

imageNext, create an instance of the class then add a new attribute with an assigned value using dot notation

chick = Bird( ‘Cheep, cheep!’ )

chick.age = ‘1 week’

imageNow, display the values in both instance variable attributes

print( ‘\nChick Says:’ , chick.talk() )

print( ‘Chick Age:’ , chick.age )

imageThen, modify the new attribute using dot notation and display its new value

chick.age = ‘2 weeks’

print( ‘Chick Now:’ , chick.age )

imageNext, modify the new attribute once more, this time using a built-in function

setattr( chick , ‘age’ , ‘3 weeks’ )

imageNow, display a list of all non-private instance attributes and their respective values using a built-in function

print( ‘\nChick Attributes...’ )

for attrib in dir( chick ) :

if attrib[0] != ‘_’ :

print( attrib , ‘:’ , getattr( chick , attrib ) )

imageFinally, remove the new attribute and confirm its removal using a built-in function

delattr( chick , ‘age’ )

print( ‘\nChick age Attribute?’ , hasattr( chick , ‘age’ ) )

imageSave then run the program – to see the instance attributes get addressed

image

image

Bird instance – chick

image

This loop skips any attribute whose name begins with an underscore, so “private” attributes will not get displayed in the list.

Deriving classes

A Python class can be created as a brand new class, like those in previous examples, or can be “derived” from an existing class. Importantly, a derived class inherits members of the parent (base) class from which it is derived – in addition to its own members.

The ability to inherit members from a base class allows derived classes to be created that share certain common properties, which have been defined in the base class. For example, a “Polygon” base class may define width and height properties that are common to all polygons. Classes of “Rectangle” and Triangle” could be derived from the Polygon class – inheriting width and height properties, in addition to their own members defining their unique features.

image

image

The virtue of inheritance is extremely powerful and is the second principle of Object Oriented Programming (OOP).

A derived class declaration adds ( ) parentheses after its class name specifying the name of its parent base class.

image

Polygon.py

imageCreate a new class file that declares a base class with two class variables and a method to set their values

class Polygon :

width = 0

height = 0

def set_values( self , width , height ) :

Polygon.width = width

Polygon.height = height

image

Rectangle.py

imageNext, create a class file that declares a derived class with a method to return manipulated class variable values

from Polygon import *

class Rectangle( Polygon ) :

def area( self ) :

return self.width * self.height

image

Triangle.py

imageNow, create another class file that declares a derived class with a method to return manipulated class variable values

from Polygon import *

class Triangle( Polygon ) :

def area( self ) :

return ( self.width * self.height ) / 2

imageSave the three class files then start a new program by making features of both derived classes available

from Rectangle import *

from Triangle import *

imageNext, create an instance of each derived class

rect = Rectangle()

trey = Triangle()

imageNow, call the class method inherited from the base class, passing arguments to assign to the class variables

rect.set_values( 4 , 5 )

trey.set_values( 4 , 5 )

imageFinally, display the result of manipulating the class variables inherited from the base class

print( ‘Rectangle Area:’ , rect.area() )

print( ‘Triangle Area:’ , trey.area() )

imageSave then run the program – to see output get displayed using inherited features

image

image

inherit.py

image

A class declaration can derive from more than one class by listing multiple base classes in the parentheses after its name in the declaration.

image

Don’t confuse class instances and derived classes – an instance is a copy of a class, whereas a derived class is a new class that inherits properties of the base class from which it is derived.

Overriding methods

A method can be declared in a derived class to override a matching method in the base class – if both method declarations have the same name and the same number of listed parameters. This effectively hides the base class method as it becomes inaccessible unless it is called explicitly, using the base class name for identification.

Where a method in a base class supplies a default parameter value this can be used in an explicit call to the base method or alternative values can be supplied by overriding methods.

image

Person.py

imageCreate a new class file that declares a base class with a initializer method to set an instance variable and a second method to display that variable value

class Person :

‘‘’A base class to define Person properties.’’’

def __init__( self , name ) :

self.name = name

def speak( self , msg = ‘(Calling The Base Class)’ ) :

print( self.name , msg )

image

Man.py

imageNext, create a class file that declares a derived class with a method that overrides the second base class method

from Person import *

‘‘’A derived class to define Man properties.’’’

class Man( Person ) :

def speak( self , msg ) :

print( self.name , ‘:\n\tHello!’ , msg )

image

Hombre.py

imageNow, create another class file that also declares a derived class with a method that once again overrides the same method in the base class

from Person import *

‘‘’A derived class to define Hombre properties.’’’

class Hombre( Person ) :

def speak( self , msg ) :

print( self.name , ‘:\n\tHola!’ , msg )

image

override.py

imageSave the three class files then start a new program by making features of both derived classes available

from Man import *

from Hombre import *

imageNext, create an instance of each derived class, initializing the “name” instance variable attribute

guy_1 = Man( ‘Richard’ )

guy_2 = Hombre( ‘Ricardo’ )

imageNow, call the overriding methods of each derived class, assigning different values to the “msg” parameter

guy_1.speak( ‘It\’s a beautiful evening.\n’ )

guy_2.speak( ‘Es una tarde hermosa.\n’ )

imageFinally, explicitly call the base class method, passing a reference to each derived class – but none for the “msg” variable so its default value will be used

Person.speak( guy_1 )

Person.speak( guy_2 )

imageSave then run the program – to see output from overriding and base class methods

image

image

Man – Richard

Hombre – Ricardo

image

The method declaration in the derived class must exactly match that in the base class to override it.

Applying sense

The three cornerstones of Object Oriented Programming (OOP) are encapsulation, inheritance, and polymorphism. Examples earlier in this chapter have demonstrated how data can be encapsulated within a Python class, and how derived classes inherit the properties of their base class. This example introduces the final cornerstone principle of polymorphism.

The term “polymorphism” (from Greek, meaning “many forms”) describes the ability to assign a different meaning, or purpose, to an entity according to its context.

image

In Python, the + character entity can be described as polymorphic because it represents either the arithmetical addition operator, in the context of numerical operands, or the string concatenation operator in the context of character operands.

Perhaps more importantly, Python class methods can also be polymorphic because the Python language uses “duck typing” – meaning... if it walks like a duck, swims like a duck, and quacks like a duck, then that bird is reckoned to be a duck.

In a duck-typed language you can create a function to take an object of any type and call that object’s methods. If the object does indeed have the called methods (is reckoned to be a duck) they are executed, otherwise the function signals a run-time error.

Like-named methods of multiple classes can be created and instances of those classes will execute the associated version.

image

Duck.py

imageCreate a new class file that declares a class with methods to display strings unique to the class

class Duck :

def talk( self ) :

print( ‘\nDuck Says: Quack!’ )

def coat( self ) :

print( ‘Duck Wears: Feathers’ )

image

Mouse.py

imageNext, create a class file that declares a class with like-named methods but to display strings unique to this class

class Mouse :

def talk( self ) :

print( ‘\nMouse Says: Squeak!’ )

def coat( self ) :

print( ‘Mouse Wears: Fur’ )

image

polymorph.py

imageSave the two class files then start a new program by making features of both classes available

from Duck import *

from Mouse import *

imageNext, define a function that accepts any single object as its parameter and attempts to call methods of that object

def describe( object ) :

object.talk()

object.coat()

imageNow, create an instance object of each class

donald = Duck()

mickey = Mouse()

imageFinally, add statements to call the function and pass each instance object to it as an argument

describe( donald )

describe( mickey )

imageSave then run the program – to see the methods of the associated versions get called

image

image

Duck – donald

image

Mouse – mickey

image

A class can have only one method with a given name – method overloading is not supported in Python.

Object Oriented Programming with Python allows data encapsulation, inheritance, and polymorphism. Base class methods can be overridden by like-named methods in derived classes. Python does not, however, support the technique of “overloading” found in other languages – in which methods of the same name can be created with different parameter lists in a single class.

Summary

•Programming objects are like virtual representations of real-world objects describing attributes and behaviors in a “class”

•A class is a data structure prototype describing object properties with its methods and attribute members

•Each class declaration begins with the class keyword and is followed by an indented code block that may contain a class document string, class variables, and class methods

•Class variables have global scope but instance variables (declared within method definitions) have only local scope

•Instance variables encapsulate data securely in a class structure and are initialized when a class instance is created

•Properties of a class are referenced by dot notation and are addressed internally using the self prefix

•A class instance is a copy of the prototype that automatically calls its __init__() method when the instance is first created

•An attribute of a class can be added, modified, or removed using dot notation or manipulated using the built-in functions getattr(), hasattr(), setattr(), and delattr()

•The name of attributes automatically supplied by Python begin with an underscore character to notionally indicate privacy

•A derived class inherits the method and attribute members of the parent base class from which it is derived

•The declaration of a derived class must state the name of its parent base class in parentheses after its own class name

•A method of a derived class can override a matching method of the same name in its parent base class

•A method of a base class can be called explicitly using the base class name for identification

•Python is a duck-typed language that supports polymorphism for like-named methods of multiple classes

•The three cornerstones of Object Oriented Programming (OOP) are Encapsulation, Inheritance, and Polymorphism