Decorator 
A decorator is an object which holds a reference to another object that you want to alter/extend the behavior of another object without inheriting from it.
python
from abc import ABC
class Shape(ABC):
    def __str__(self):
        return ''
class Circle(Shape):
    def __init__(self, radius=0.0):
        self.radius = radius
    def resize(self, factor):
        self.radius *= factor
    def __str__(self):
        return f'A circle of radius {self.radius}'
class Square(Shape):
    def __init__(self, side):
        self.side = side
    def __str__(self):
        return f'A square with side {self.side}'
class ColoredShape(Shape):
    def __init__(self, shape, color):
        if isinstance(shape, ColoredShape):
            raise Exception('Cannot apply ColoredDecorator twice')
        self.shape = shape
        self.color = color
    def __str__(self):
        return f'{self.shape} has the color {self.color}'
class TransparentShape(Shape):
    def __init__(self, shape, transparency):
        self.shape = shape
        self.transparency = transparency
    def __str__(self):
        return f'{self.shape} has {self.transparency * 100.0}% transparency'
if __name__ == '__main__':
    circle = Circle(2)
    print(circle)
    red_circle = ColoredShape(circle, "red")
    print(red_circle)
    # ColoredShape doesn't have resize()
    # red_circle.resize(3)
    red_half_transparent_square = TransparentShape(red_circle, 0.5)
    print(red_half_transparent_square)
    # nothing prevents double application
    mixed = ColoredShape(ColoredShape(Circle(3), 'red'), 'blue')
    print(mixed)Dynamic Decorator 
You can also have a Dynamic Decorator by passing calls to access the underlying item.
python
class FileWithLogging:
  def __init__(self, file):
    self.file = file
  def writelines(self, strings):
    self.file.writelines(strings)
    print(f'wrote {len(strings)} lines')
  def __iter__(self):
    return self.file.__iter__()
  def __next__(self):
    return self.file.__next__()
  def __getattr__(self, item):
    return getattr(self.__dict__['file'], item)
  def __setattr__(self, key, value):
    if key == 'file':
      self.__dict__[key] = value
    else:
      setattr(self.__dict__['file'], key)
  def __delattr__(self, item):
    delattr(self.__dict__['file'], item)
if __name__ == '__main__':
  file = FileWithLogging(open('hello.txt', 'w'))
  file.writelines(['hello', 'world'])
  file.write('testing')
  file.close()Functional Decorators 
Functional decorators are built in to python to alter the behavior of your functions.
python
import time
def time_it(func):
    def wrapper():
        start = time.time()
        result = func()
        end = time.time()
        print(f'{func.__name} took {int(end-start) * 1000}ms')
        return result
    return wrapper
@time_it
def some_op():
    print('Starting op')
    time.sleep(1)
    print('Finished op')
    return 123
if __name__ == '__main__':
    some_op()