This is the material for SANS Webcast where we deep dive into the internals of how Python Decorators work. To understand this material you will want to watch the associated presentation.
The registration link is here: https://www.sans.org/webcasts/python-decorators-demystified-108900
(update) The talk has been archived here : https://www.youtube.com/watch?v=M4FrdJKGwX4&t=1981s
x = print
x("Hello {}, what is your {}".format("sir robin", "quest"))
Watch it execute Click Here
def newfunc(input_arg=10):
local1 = 100
local2 = 5
local3 = local1+local2
return
newfunc.__code__.co_varnames, newfunc.__code__.co_consts
newfunc.__code__.co_code
Watch it execute Click Here
def print_in_color(color):
def colored_print(*args,**kwargs):
print("Set Screen Color to {0}".format(color))
print(*args,**kwargs)
return None
return colored_print
red_print = print_in_color("RED")
blue_print = print_in_color("BLUE")
red_print("mark was here")
blue_print("mark was not here")
Watch it execute Click Here
red_print.__code__.co_varnames, red_print.__code__.co_consts
And a special attrubute named closure hold the contents of any function dependencies that have existed
red_print.__closure__[0].cell_contents
red_print.__code__.co_freevars
Watch this execute Click Here
def wrap_function_with_prints(function_to_call):
def newfunc(*args, **kwargs):
print("about to call {0}".format(str(function_to_call)))
function_to_call(*args, **kwargs)
print("called")
return newfunc
def sayhi():
print("HI!")
sayhi()
x = wrap_function_with_prints(sayhi)
x()
Lets try to wrap a function that takes arguments also..
def add(num1,num2):
print("{}+{}={}".format(num1,num2,num1+num2))
x = wrap_function_with_prints(add)
x(10,35)
Most often you overwrite the original function with the new decorated function
sayhi = wrap_function_with_prints(sayhi)
sayhi()
This is an alternative syntax for doing the same thing
@wrap_function_with_prints
def sayhi():
print("HI!")
@wrap_function_with_prints
def sayhi():
print("HI!")
@wrap_function_with_prints
def saybye():
print("BYE!")
@wrap_function_with_prints
def add(n1,n2):
print("sum is", n1+n2)
@wrap_function_with_prints
def sayanything(anything):
print(anything)
Watch it execute Click Here
def decorator_with_args(item1, item2):
def decorator_factory(function_to_call):
print("{0} {1} {2}".format(item1, item2, str(function_to_call)))
def wrapped_f(*args,**kwargs):
print("about to call")
print("Decorator arguments:", item1, item2, str(args), str(kwargs))
function_to_call(*args,**kwargs)
print("called")
return wrapped_f
return decorator_factory
def say(what):
print(what)
x = decorator_with_args("SEC573","ROCKS")(say)
x("UH HUH")
@decorator_with_args("SEC573","ROCKS")
def say(what):
print(what)
say("I've been decorated!!!")
import functools
def time_this(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
"This calculates run times"
start_time= datetime.datetime.now()
ret = func(*args,**kwargs)
elapsed = datetime.datetime.now()- start_time
print("The function {} took {}.{} seconds".format(func.__name__, elapsed.seconds, elapsed.microseconds))
return ret
return wrapper
from subprocess import Popen,PIPE
@time_this
def exec_cmd(cmd):
"Run a command and capture the output"
out,err = Popen(cmd,shell=True,stderr=PIPE,stdout=PIPE).communicate()
return out+err