13.2. Object-oriented Programming

The evolution of programming has taken us from a sequence of step-by-step instructions in a single flow of control to a more organized approach whereby blocks of code could be cordoned off into named subroutines and defined functionality. Structured or procedural programming lets us organize our programs into logical blocks, often repeated or reused. Creating applications becomes a more logical process; actions are chosen which meet the specifications, then data is created to be subjected to those actions. Deitel & Deitel refer to structured programming as “action-oriented” due to the fact that logic must be “enacted” on data which has no associated behaviors.

However, what if we could impose behavior on data? What if we were able to create or program a piece of data modeled after real-life entities which embodies both data characteristics along with behaviors? If we were then able to access the data attributes via a set of defined interfaces (a.k.a. a set of accessor functions), such as an automated teller machine (ATM) card or a personal check to access your bank account, then we would have a system of “objects” where each could interact not only with itself, but also with other objects in a larger picture.

Object-oriented programming takes this evolutionary step by enhancing structured programming to enable a data/behavior relationship: Data and logic are now described by a single abstraction with which to create these objects. Real-world problems and entities are stripped down to their bare essentials, providing that abstraction from which they can be coded or implemented into objects and be able to interact with other objects in the system which models and hopefully solves these problems. Classes provide the definitions of such objects, and instances are realizations of such definitions. Both are vital components for object-oriented design (OOD), which simply means to build your system architected in an object-oriented fashion.

13.2.1. Relationship between OOD and OOP

Object-oriented design does not specifically require an object-oriented programming language. Indeed, OOD can be performed in purely structural languages such as C, but this requires more effort on the part of the programmer who must build data types with object qualities and characteristics. Naturally, OOP is simplified when a language has built-in OO properties that enable smoother and more rapid development of OO programs.

Conversely, an object-oriented language does not necessarily force one to write OO programs. C++ can be used simply as a “better C.” As you are no doubt aware, neither classes nor OOP are required for everyday Python programming. Even though it is a language which is object-oriented by design and which has constructs to support OOP, Python does not restrict nor require you to write OO code for your application. Rather, OOP is a powerful tool which is at your disposal when you are ready to evolve, learn, transition, or otherwise move towards OOP. The creator of Python often refers to this phenomena as being able to “see the forest through the trees.”

13.2.2. Real-world Problems

One of the most important reasons to consider working in OOD is that it provides a direct approach to modeling and solving real-world problems and situations. For example, let us attempt to model an automobile mechanic shop where you would take your car in for repair. There are two general entities we would have to create: humans who interact with and in such a “system,” and a physical location for the activities which define a mechanic shop. Since there are more of and different types of the former, we will describe them first, then conclude with the latter.

A class called Person would be created to represent all humans involved in such an activity. Instances of Person would include the Customer, the Mechanic, and perhaps the Cashier. Each of these instances would have similar as well as unique behaviors. For example, all would have the talk() method as a means of vocal communication as well as a drive_car() method. Only the Mechanic would have the repair_car() method and only the Cashier would have a ring_sale() method. The Mechanic will have a repair_certification attribute while all Persons would have a drivers_license attribute.

Finally, all of these instances would be participants in one overseeing class, called the RepairShop, which would have operating_hours, a data attribute which accesses time functionality to determine when Customers can bring in their vehicles and when Employees such as Mechanics and Cashiers show up for work. The RepairShop might also have a AutoBay class which would have instances such as SmogZone, TireBrakeZone, and perhaps one called GeneralRepair.

The point of our fictitious RepairShop is to show one example of how classes and instances plus their behaviors can be used to model a true-to-life scenario. You can probably also imagine classes such as an Airport, a Restaurant, a ChipFabPlant, a Hospital, or even a MailOrderMusic business, all complete with their own participants and functionality.

13.2.3. *Buzzword-compliance

For those of you who are already familiar with all the lingo associated with OOP, here is how Python stacks up:

Abstraction/Implementation

Abstraction refers to the modeling of essential aspects, behavior, and characteristics of real-world problems and entities, providing a relevant subset as the definition of a programmatic structure which can realize such models. Abstractions not only contain the data attributes of such a model, but also define interfaces with that data. An implementation of such an abstraction is the realization of that data and the interfaces which go along with it. Such a realization should remain hidden from and irrelevant to the client programmer. Class objects in Python provide the ability to create such abstractions, and implementation details are left to the designer.

Encapsulation/Interfaces

Encapsulation describes the concept of data/information hiding and providing interfaces or accessor functions to the data attributes. Direct access to data by any client, bypassing the interfaces, goes against the principles of encapsulation, but the programmer is free to allow such access. As part of the implementation, the client should not even know how the data attributes are architected within the abstraction. In Python, all class attributes are public, but names may be “mangled” to discourage unauthorized access, but otherwise not prevented. It is up to the designer to provide the appropriate interfaces to the data so that the client programmer does not have to resort to manipulating the encapsulated data attributes.

Composition

Composition extends our description of classes, enabling multiple yet distinct classes to be combined into a larger entity to solve a real-world problem. Composition describes a singular, complex system such as a class made up of other, smaller components such as other classes, data attributes, and behaviors, all of which are combined, embodying “has-a” relationships. For example, the RepairShop “has a” Mechanic (hopefully at least one) and also “has a” Customer (again, hopefully at least one).

These components are composed either via association, meaning that access to subcomponents is granted (for the RepairShop, a customer may enter and request a SmogCheck, the client programmer interfacing with components of the RepairShop), or aggregation, encapsulating components which are then accessed only via defined interfaces, and again, hidden from the client programmer. Continuing our example, the client programmer may be able to make a SmogCheck request on behalf of the Customer, but has no ability to interact with the SmogZone part of the RepairShop which is accessed only via internal controls of the RepairShop when the smogCheckCar() method is called. Both forms of composition are supported in Python.

Derivation/Inheritance/Hierarchy

Derivation describes the creation of subclasses, new classes which retain all desired data and behavior of the existing class type but permit modification or other customization, all without having to modify the original class definition. Inheritance describes the means by which attributes of a subclass are “bequeathed from” an ancestor class. From our earlier example, a Mechanic may have more car skill attributes than a Customer, but individually, each “is a” Person, so it is valid to invoke the talk() method, which is common to all instances of Person, for either of them. Hierarchy describes multiple “generations” of derivation which can be depicted graphically as a “family tree,” with successive subclasses having relationships with ancestor classes.

Generalization/Specialization

Generalization describes all the traits a subclass has with its parent and ancestor classes, so subclasses are considered to have an “is-a” relationship with ancestor classes because a derived object (instance) is an “example” of an ancestor class. For example, a Mechanic “is a” Person, a Car “is a” Vehicle, etc. In the family tree diagram we alluded to above, we can draw lines from subclasses to ancestors indicating “is-a” relationships. Specialization is the term which describes all the customization of a subclass, i.e., what attributes which make it differ from its ancestor classes.

Polymorphism

The concept of polymorphism describes how objects can be manipulated and accessed using attributes and behaviors they have in common without regard to their specific class. Polymorphism indicates the presence of dynamic (a.k.a. late, run-time) binding, allowing for overloading and run-time type determination and verification. Many OO languages use “signatures” to determine which version of an overloaded method to call, but since Python calls are universal or generic without type determination, overloading is unnecessary and is not supported in the language.

Introspection/Reflection

Introspection is what gives you, the programmer, the ability to perform an activity such as “manual type checking.” Also called reflection, this property describes how information about a particular object can be accessed by itself during run-time. Would it not be great to have the ability to take an object passed to you and be able to find out what it is capable of? This is a powerful feature which you will encounter frequently in this chapter. The dir() and type() built-in functions would have a very difficult time working if Python did not support for some sort of introspection capability. Keep an eye out for these calls as well as for special attributes like __dict__, __name__, __doc__, __members__, and __methods__. You may even be familiar with some of them already!

CORE NOTE: Use of the terms “object” and “type” in Python

In other object-oriented programming languages, the term “object” may refer specifically to class instances, even more so when all data types of those languages are classes. Not so with Python. Because data types in Python are not classes, not all objects are, therefore, class instances.

Some languages also consider defining a class to be synonymous with creating a new type. Again, this is not the case with Python, but it is similar. Python has a fixed number of predefined types and these remain constant. (Creating a new type in Python is a non-trivial task, requiring implementation as an extension, and it is out of the scope of this text.) When creating classes, you can give them behavior characteristics of types but they are not considered types.

However, Python is an object-oriented programming language and considers all entities generically as objects because they do share some common semantics, yet are still distinct enough to be different types of objects. In summary, classes, instances, and types are not related to each other (with the exception that a class defines an object which is realized as an instance, another type of object).

Bottom line: (all) classes are class objects, (all) instances are instance objects, neither are types, and everything is an object. Also see the Core Note in Section 13.5.1.


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

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