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.

7.2.1 R Scripting

7.2.2 Python Scripting