7 Object-Oriented Programming with R and Python
At this point we are ready to expand our exploration with object-oriented programming (OOP) in R and Python. Objects are like (collections of one or more) functions with some added structure. This structure has been defined by the four principles which set apart OOP.
- Abstarction .
- Encapsulation .
- Inheritance .
- Polymorphism .
Additionally the functions an object contains, called it’s methods are conceptualized as relating to the actions of the object. The methods are actions which are done by the object for itself - an add method enables the object to add itself. A square object would add something to itself in an internally defined fashion.
Consider a function/method to transparently operates on a variable as would be appropriate to the data-type. This is polymorphism, a consequence of the message-passing model. An ‘add’ method would do some sort of add operation in a fashion appropriate to the object and the input, and it would do it by passing a “do add”" message into the blackbox of the object and the details are inaccessible to the user. Access to the objects characteristics is also by such methods and in no other way. This is encapsulation or ‘information hiding’.
You can only alter an object itself by extending it’s pattern in a new object. All the things of the old object are passed on and exist in the new object by re-inplementation of old characteristics and new characteristics and behaviors are implemented on top of the parent object’s pattern. This is inheritance.
As above the object has control over how it is seen in the environment external to the object. The picture the object releases is an abstraction of it’s pattern definition and contents. The totality of object data structure emerges from the outputs of the object methods.
A generic class pattern or definition (in pseudocode) consists of a class signature (or name) and a contained code block with class details. This is the fundamental abstraction which is an object. It could be represented like this,
# Class indentity
class() [ include inheritance]
#Class details
# the characteristics
class constants
class variables
# instance creation
constructor()
# class actions
methods()
7.1 Defining Classes in R and Python
A class is a specific object pattern, The automobile class is an object with wheels, some mode of propulsion and driver methods. A class instance is a particular realization of car with specifics values added to characteristics inherited from the class.
R, Functions or Classes
Due to how it evolved, R has at least 3 kinds or levels of objects, developed in a chronologic order. These all, arguably, then strain the limits of what is or is not Object-Oriented. The explanation offered22 is the origin of R from S as an interactive environment and further development faces compromises to this. It can be used as a scripting language, even as if running programs but at the base of it all the interpreter runs the scripts in the the main over it’s interactive nature.
I think in an important sense none of the OOP attempts fit the bill. Witness that there are 3 attempts to provide an R environment for Object-Oriented development and all have different shortcomings in the implementation. Add further what is actually a 4th object-oriented-type, but outside of core-R, with the R6 Package. Summarizing,
- (predominantly genertic functions without formal class definition)
- (Class definitions)
- RC (es, or ‘euphemistically’ S5 or )
- (External to Core-R R6 package)
The result of all this is that only the masochistically R obscessed or extreme programmer ventures here. R scripting afficionados even with lots of time proceed with caution.
I learned Object-Oriented Programming with Java and statistics with R. After a look further inside R for OOP, I decided I wasn’t going there - all the more reason for adding Python to one’s Data Science repertoir.
I am not going to explore R OOP beyond the discussion under calling R objects below, really a syntatic variant of functional programming. Those readers truly coming from R will understand.
Python Objects
In contrast to R python Object-Oriented Programming meets nearly everybody’s understanding of OOP. Python Objects when instantiated look, feel and behave like an object for me. The python system of namespaces s and variable visability blend consistently with the idea of encapsulation and data-hiding.
Python objects inherit from parent objects as expected and polymorphism operates behind the object envelope transparently and as one logicall expects for data-types or structures. Abstraction is a conceptualization of the data-structres created as objects.
Lets create a simple python class8-p627 like,
# python code
class SimpleClass:
# Define the class object
# Note: Implied constructor is
# that of the base object of
# the python environment.
# Define class methods
def setdata(self, value): # a value 'setter' method
self.value = value # \index{self} is the instance itself
def getdata(self): # a value 'getter' method
print(self.value)
# create object instance from class definition
x = SimpleClass()
x.setdata(5) # x became '\index{self}' in the abstract
x.getdata() # what is the value of x
## 5
print(x.value)
## 5
Well, now we just accessed the value of x directly - not hidden data as we should expect.
Let’s try another, the ubiquitous Car example .
# what is a car?
class Car:
_motor = ""
_style = ""
_year = ""
def __init__(self, year, style, motor): # constructor, always an __init__ function
self._motor=motor
self._style=style
self._year=year
def setmotor(self, motor): # setters
self._motor=motor
def setstyle(self, style):
self._style=style
def getmotor(self): # getters
return _self.motor
def getstyle(self):
return _self.style
def toString(self):
return (self._year+","+self._motor+","+self._style)
# build a car
Newcar = Car('2019','Sedan', '4 cylinder gasoline' )
# What is 'our' Newcar?
print(Newcar)
## <__main__.Car object at 0x0000000062A03898>
OOoops I printed out the object info not the instance data!
What happens if I try direct access to an instance variable ‘style’?
print(Newcar.style)
We get an error,
Error in py_run_string_impl(code, local, convert) :
AttributeError: 'Car' object has no attribute 'style'
Detailed traceback:
File "<string>", line 1, in <module>
Calls: <Anonymous> ... py_capture_output -> force -> py_run_string -> py_run_string_impl
Execution halted
Unfortunately, it is still accessible but you need to use the internal name ’_style’
print(Newcar._style)
## Sedan
Well in terms of encapsulation in python OOP, close but no cigar. But as leandrotk notes in this blog
Non-public variables are just a convention and should be treated as a non-public part of the API.
That means when we see the leading underscore weare ‘pretending’ the variable is private. The responsibility rests with the programmer. The only way to control it at all is to not document the underscore for the object’s API.
Now try again using the object’s own print method.
print(Newcar.toString())
## 2019,4 cylinder gasoline,Sedan
What about inheritance? Let’s subclass the car as a truck.
class Truck(Car):
_type = ""
def __init__(self, year, style, motor, type):
super().__init__(year, style, motor)
self._type = type
def toString(self):
return super().toString() + "," + self._type
Bigtruck = Truck('2018','Truck','6 cylinder diesel', 'box' )
print(Bigtruck.toString())
## 2018,6 cylinder diesel,Truck,box
We have used the car pattern, referring to it as the superclass super. and we have overridden the tostring function to include the _type variable appended to the car string.
7.2 Using Objects and Classes
An instance of a class is created by the class constructor . An object constructor is implicitly inherited by all classes, from the language’s object definition and implementation. It is often explicitly overridden by a customized contructor.