How to Create Decorators in R

Articles From: TheAutomatic.net
Website: TheAutomatic.net

By:

Blogger, TheAutomatic.net, and Senior Data Scientist

Introduction

One of the coolest features of Python is its nice ability to create decorators. In short, decorators allow us to modify how a function behaves without changing the function’s source code. This can often make code cleaner and easier to modify. For instance, decorators are also really useful if you have a collection of functions where each function has similar repeating code. Fortunately, decorators can now also be created in R!

The first example below is in Python – we’ll get to R in a moment. If you already know about decorators in Python, feel free to skip below to the R section.

Below we have a function that prints today’s date. In our example, we create two functions. The first – print_start_end takes another function as input. It prints “Starting function call…” prior to calling this input function. Secondly, it calls the function. Lastly, it prints “Finished function call…”.

The other function, todays_date, simply prints today’s date.

import datetime
 
# defining a decorator 
def print_start_end(f): 
     
    def wrapper(**args): 
        print("Starting function call...") 
   
        f() 
   
        print("Finished function call...") 
           
    return wrapper 
      
def todays_date(): 
     print(datetime.datetime.today())

Now, let’s say we want to call our todays_date function, but would like to wrap it inside the print_start_end function. One way to do that is by having a nested function call:

print_start_end(todays_date)

However, we can also add a decorator to the todays_date like below. In Python, a decorator is created by adding an “@” followed by a function name (the “decorating” function).

@print_start_end   
def todays_date(): 
     print(datetime.datetime.today())

The result of running todays_date() now is below:

 wp-image-175172

We get the same result using a decorator as we did using a nested function call above. The nice part of this, however, is that we don’t have to have any nested functions or change the code within todays_date. We can also easily comment out the decorator to turn off this functionality if we wanted to.

#@print_start_end   
def todays_date(): 
     print(datetime.datetime.today())

There’s a whole lot more to decorators. To learn more, check out Powerful Python, or Guide to Learning Python Decorators. The second of these resources focuses solely on decorators, while the first one also covers several other Python features.

Decorators in R

Now, let’s walk through how to create decorators in R. We can do that using an awesome package called tinsel.

To get started, we first need to install tinsel, which requires devtools. If you don’t have the devtools package installed, you’ll need to install that first (install.packages(“devtools”)). Then, you can install tinsel by running the command below.

devtools::install_github('nteetor/tinsel')

Once you’re setup, you can start decorating functions. Let’s recreate the example above using R. The first function is straightforward to reproduce – we’re just changing Python syntax to R.

library(tinsel)
 
print_start_end <- function(f)
{
  wrapper <- function(...)
  {
      print("Starting function call...") 
   
      f() 
   
      print("Finished function call...") 
   
  }
     
  return(wrapper) 
   
}

Now when it comes to the function we’re decorating – todays_date, we add our decorator using “#.” plus the name of our decorator function – in this case, print_start_end. Essentially, the main difference between creating a decorator here in R vs. Python is that we use “#.” rather than an “@” in the line above a function to signify that we want to decorate that function.

#. print_start_end
todays_date <- function()
{
    print(Sys.Date())
   
}

In order for R to recognize that we want to use decorators, we need to source our R script using tinsel’s source_decoratees function. Here we just need to pass the name of our script.

source_decoratees("test_dec.R")

Now when we call todays_date, the decorated version of the function gets executed.

 wp-image-175182

As mentioned, one key use of decorators is to handle collections of functions that have similar repeating lines of code. For example, let’s apply the print_start_end decorator above to two other functions.

#. print_start_end
yesterday <- function()
{
    print(Sys.Date() - 1)
   
}
 
#. print_start_end
tomorrow <- function()
{
  print(Sys.Date() + 1)
   
}
 wp-image-175188

Timing functions with an R decorator

Another nice feature of decorators is that if we make changes to the decorator, we can easily apply these to any of the functions being decorated. For example, below we can change our print_start_end function to time the execution of a function.

print_start_end <- function(f)
{
  wrapper <- function(...)
  {
      start <- proc.time() 
   
      f() 
   
      print(proc.time() - start) 
   
  }
     
  return(wrapper) 
   
}

Then, we can call our functions like below with our updated decorator. This allows us to make changes once rather than for each function.

yesterday()
 
tomorrow()
 wp-image-175189

That’s all for now! Please click to follow my blog on Twitter and keep up with my latest posts, or check out some additional resources for learning Python and R by clicking here.

Originally posted on TheAutomatic.net.

Disclosure: Interactive Brokers

Information posted on IBKR Campus that is provided by third-parties does NOT constitute a recommendation that you should contract for the services of that third party. Third-party participants who contribute to IBKR Campus are independent of Interactive Brokers and Interactive Brokers does not make any representations or warranties concerning the services offered, their past or future performance, or the accuracy of the information provided by the third party. Past performance is no guarantee of future results.

This material is from TheAutomatic.net and is being posted with its permission. The views expressed in this material are solely those of the author and/or TheAutomatic.net and Interactive Brokers is not endorsing or recommending any investment or trading discussed in the material. This material is not and should not be construed as an offer to buy or sell any security. It should not be construed as research or investment advice or a recommendation to buy, sell or hold any security or commodity. This material does not and is not intended to take into account the particular financial conditions, investment objectives or requirements of individual customers. Before acting on this material, you should consider whether it is suitable for your particular circumstances and, as necessary, seek professional advice.