Functions as objects
WRITING FUNCTIONS IN PYTHON
Shayne Miel
Software Architect @ Duo Security
Functions are just another type of object
Python objects:
def x():
pass
x = [1, 2, 3]
x = {'foo': 42}
x = [Link]()
x = 'This is a sentence.'
x = 3
x = 71.2
import x
WRITING FUNCTIONS IN PYTHON
Functions as variables
def my_function():
print('Hello')
x = my_function
type(x)
<type 'function'>
x()
Hello
PrintyMcPrintface = print
PrintyMcPrintface('Python is awesome!')
Python is awesome!
WRITING FUNCTIONS IN PYTHON
Lists and dictionaries of functions
list_of_functions = [my_function, open, print]
list_of_functions[2]('I am printing with an element of a list!')
I am printing with an element of a list!
dict_of_functions = {
'func1': my_function,
'func2': open,
'func3': print
}
dict_of_functions['func3']('I am printing with a value of a dict!')
I am printing with a value of a dict!
WRITING FUNCTIONS IN PYTHON
Referencing a function
def my_function():
return 42
x = my_function
my_function()
42
my_function
<function my_function at 0x7f475332a730>
WRITING FUNCTIONS IN PYTHON
Functions as arguments
def has_docstring(func): def no():
"""Check to see if the function return 42
`func` has a docstring.
def yes():
Args: """Return the value 42
func (callable): A function. """
return 42
Returns:
bool
has_docstring(no)
"""
return func.__doc__ is not None
False
has_docstring(yes)
True
WRITING FUNCTIONS IN PYTHON
Defining a function inside another function
def foo():
x = [3, 6, 9]
def bar(y):
print(y)
for value in x:
bar(x)
WRITING FUNCTIONS IN PYTHON
Defining a function inside another function
def foo(x, y):
if x > 4 and x < 10 and y > 4 and y < 10:
print(x * y)
def foo(x, y):
def in_range(v):
return v > 4 and v < 10
if in_range(x) and in_range(y):
print(x * y)
WRITING FUNCTIONS IN PYTHON
Functions as return values
def get_function():
def print_me(s):
print(s)
# returns the function 'print_me'
return print_me
new_func = get_function()
new_func('This is a sentence.')
This is a sentence.
WRITING FUNCTIONS IN PYTHON
Let's practice!
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Shayne Miel
Software Architect @ Duo Security
Names
WRITING FUNCTIONS IN PYTHON
Names
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Scope
x = 7 foo()
y = 200
print(x)
42
200
7
print(x)
def foo():
x = 42
7
print(x)
print(y)
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
Scope
WRITING FUNCTIONS IN PYTHON
The global keyword
x = 7 x = 7
def foo(): def foo():
x = 42 global x
print(x) x = 42
print(x)
foo()
foo()
42
42
print(x)
print(x)
7
42
WRITING FUNCTIONS IN PYTHON
The nonlocal keyword
def foo(): def foo():
x = 10 x = 10
def bar(): def bar():
x = 200 nonlocal x
print(x) x = 200
print(x)
bar()
print(x) bar()
print(x)
foo()
foo()
200
10 200
200
WRITING FUNCTIONS IN PYTHON
Let's practice!
WRITING FUNCTIONS IN PYTHON
Closures
WRITING FUNCTIONS IN PYTHON
Shayne Miel
Software Architect @ Duo Security
Attaching nonlocal variables to nested functions
def foo(): Closures!
a = 5
def bar():
type(func.__closure__)
print(a)
return bar
<class 'tuple'>
func = foo()
len(func.__closure__)
func()
1
5
func.__closure__[0].cell_contents
WRITING FUNCTIONS IN PYTHON
Closures and deletion
x = 25 len(my_func.__closure__)
def foo(value):
1
def bar():
print(value)
return bar my_func.__closure__[0].cell_contents
my_func = foo(x)
my_func() 25
25
del(x)
my_func()
25
WRITING FUNCTIONS IN PYTHON
Closures and overwriting
x = 25 len(x.__closure__)
def foo(value):
1
def bar():
print(value)
return bar x.__closure__[0].cell_contents
x = foo(x)
25
x()
25
WRITING FUNCTIONS IN PYTHON
Definitions - nested function
Nested function: A function defined inside another function.
# outer function
def parent():
# nested function
def child():
pass
return child
WRITING FUNCTIONS IN PYTHON
Definitions - nonlocal variables
Nonlocal variables: Variables defined in the parent function that are used by the child
function.
def parent(arg_1, arg_2):
# From child()'s point of view,
# `value` and `my_dict` are nonlocal variables,
# as are `arg_1` and `arg_2`.
value = 22
my_dict = {'chocolate': 'yummy'}
def child():
print(2 * value)
print(my_dict['chocolate'])
print(arg_1 + arg_2)
return child
WRITING FUNCTIONS IN PYTHON
Closure: Nonlocal variables attached to a returned function.
def parent(arg_1, arg_2):
value = 22
my_dict = {'chocolate': 'yummy'}
def child():
print(2 * value)
print(my_dict['chocolate'])
print(arg_1 + arg_2)
return child
new_function = parent(3, 4)
print([cell.cell_contents for cell in new_function.__closure__])
[3, 4, 22, {'chocolate': 'yummy'}]
WRITING FUNCTIONS IN PYTHON
Why does all of this matter?
Decorators use:
Functions as objects
Nested functions
Nonlocal scope
Closures
WRITING FUNCTIONS IN PYTHON
Let's practice!
WRITING FUNCTIONS IN PYTHON
Decorators
WRITING FUNCTIONS IN PYTHON
Shayne Miel
Software Architect @ Duo Security
Functions
WRITING FUNCTIONS IN PYTHON
Decorators
WRITING FUNCTIONS IN PYTHON
Modify inputs
WRITING FUNCTIONS IN PYTHON
Modify outputs
WRITING FUNCTIONS IN PYTHON
Modify function
WRITING FUNCTIONS IN PYTHON
What does a decorator look like?
@double_args
def multiply(a, b):
return a * b
multiply(1, 5)
20
WRITING FUNCTIONS IN PYTHON
The double_args decorator
def multiply(a, b):
return a * b
def double_args(func):
return func
new_multiply = double_args(multiply)
new_multiply(1, 5)
multiply(1, 5)
WRITING FUNCTIONS IN PYTHON
The double_args decorator
def multiply(a, b):
return a * b
def double_args(func):
# Define a new function that we can modify
def wrapper(a, b):
# For now, just call the unmodified function
return func(a, b)
# Return the new function
return wrapper
new_multiply = double_args(multiply)
new_multiply(1, 5)
WRITING FUNCTIONS IN PYTHON
The double_args decorator
def multiply(a, b):
return a * b
def double_args(func):
def wrapper(a, b):
# Call the passed in function, but double each argument
return func(a * 2, b * 2)
return wrapper
new_multiply = double_args(multiply)
new_multiply(1, 5)
20
WRITING FUNCTIONS IN PYTHON
The double_args decorator
def multiply(a, b):
return a * b
def double_args(func):
def wrapper(a, b):
return func(a * 2, b * 2)
return wrapper
multiply = double_args(multiply)
multiply(1, 5)
20
multiply.__closure__[0].cell_contents
<function multiply at 0x7f0060c9e620>
WRITING FUNCTIONS IN PYTHON
Decorator syntax
def double_args(func): def double_args(func):
def wrapper(a, b): def wrapper(a, b):
return func(a * 2, b * 2) return func(a * 2, b * 2)
return wrapper return wrapper
@double_args
def multiply(a, b): def multiply(a, b):
return a * b return a * b
multiply = double_args(multiply)
multiply(1, 5) multiply(1, 5)
20 20
WRITING FUNCTIONS IN PYTHON
Let's practice!
WRITING FUNCTIONS IN PYTHON