Decorator Basics and Class Decorators¶
Decorator Overview¶
Decorators provide a simple syntax for calling higher-order functions. By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. Sounds confusing—but it’s really not, especially after we go over a number of examples.
A simple example
def wrapper(f):
def inner_func(*args,**kwargs):
start_time = time.time()
c = f(*args,**kwargs)
end_time = time.time()
print(end_time - start_time)
return c
return inner_func
@wrapper
def add(x,y):
return x + y
@wrapper
def subtract(x,y):
return x - y
sum = add(5,10)
print(sum)
A decorator is something that makes your code look clean and well written. In OOP decorators are common place. There are a few decorators that are provided out of the box from python. They are listed below.
Decorators are elegant! Makes code look cleaner and trimmer
Out-of the box function decorators that can come in handy¶
@property
@classmethod
@staticmethod
@property -Getters, setters, deleters¶
- The property decorator allows us to define Class methods that we can access like attributes. This allows us to implement getters, setters, and deleters
class Employee:
def __init__(self, first, last):
self.first = first
self.last = last
@property
def email(self):
return '{}.{}@email.com'.format(self.first, self.last)
@property
def fullname(self):
return '{} {}'.format(self.first, self.last)
emp_1 = Employee('John', 'Smith')
print(emp_1.first)
print(emp_1.email)
print(emp_1.fullname)
@classmethod¶
- Classmethods takes
cls
as a parameter instead ofself
- Classmethods don’t modify the state of the instance they modify class state and this change applies across all instances.
A typical example of a function generated by @classmethod
decorator
@classmethod
def increase_count(cls,counter):
cls.counter += counter
@staticmethod¶
- Staticmethod is a method that takes no parameter but is still is a logical part of the class this method is neither bound by an instance or a class
@staticmethod
def is_holiday(day):
if day.weekday() == 5 or day.weekday() == 6:
return True
return False
A combined example is shown below
#Class Method as a constructor
import datetime
class DateTimeParser:
counter = 0
def __init__(self,d=None,m=None,y=None):
self.d, self.m,self.y = d,m,y
@classmethod
def parse(cls,datestring):
date,month,year = datestring.split("/")
return cls(date,month,year)
@classmethod
def increase_count(cls,counter):
cls.counter += counter
@staticmethod
def is_holiday(day):
if day.weekday() == 5 or day.weekday() == 6:
return True
return False
if __name__ == "__main__":
date1 = DateTimeParser.parse("12/05/2015")
print(DateTimeParser().counter)
print(date1.counter)
DateTimeParser().increase_count(10)
print(date1.counter)
print(DateTimeParser().counter)
Class Decorators¶
Class decorators are similar to function decorators, but they are run at the end of a class statement to rebind a class name to a callable. As such, they can be used to either manage classes just after they are created, or insert a layer of wrapper logic to manage instances when they are later created.
def decorator(cls): # On @ decoration
class Proxy:
def __init__(self, *args): # On instance creation: make a cls
self.wrapped = cls(*args)
def __getattr__(self, name): # On attribute fetch: extra ops
return getattr(self.wrapped, name)
return Proxy
@decorator
class C:
pass
x = C()
Note
Work in progress