# Comparison of performance of def and lambda functions. So all the same speed or readability?

## Idea for code

Reading pep8, I came across an item about using anonymous functions – according to pep’s version, they reduce readability, if you use a variable with a function value as a function, it is better to use def. I decided to compare def and lambda in another parameter – performance. I assumed that lambda, sharpened for one-liners, would be faster to execute and create. In this study, I will test it.

## Libraries

Since there will be many time measurements, we will undoubtedly need a time library, as well as a turtle, to draw all sorts of charts. I know this is impractical, but matprolib takes too long (10 seconds) to import. So:

``````from turtle import *
from time import time``````

## Common functions

In our code, to measure performance, we need … a function to measure performance. It will be the main one for all derivatives. First of all, we will not measure the execution time once, the error is too large. The function will accept as arguments the function for which the measurement is performed, as well as the number of repetitions of this function.

For the measurement itself, we will use the time difference between the start of execution and the end. The code is formed from the description:

``````def speed_test(func, n):
start = time()
for i in range(n):
func()
stop = time()
return stop - start``````

In total, we will have 2 diagrams – full and average. Each has 2 graphs – for def and lambda functions. In total we need 4 turtles.

The list of values ​​for 1 and 2 of the graph is obvious – several results of the speed measurement. With 3 and 4, everything is more difficult – you need to find the arithmetic mean of one of the first 2 graphs. In order not to bother too much so that the graph does not get out anywhere, we will find the difference between each element of each graph and the average value between the arithmetic means from 1 and 2 of the graph. As a result, on the chart we will see not the total value, but the difference.

We will put all the graphs into a common dictionary so as not to create many variables. The dictionary is pre-declared outside of the function

``````def graph_data(func1, func2, mult1, mult2, arr_len):
l['l1'] = [func1(mult1)*mult2 for i in range(arr_len)]
l['l2'] = [func2(mult1)*mult2 for i in range(arr_len)]
l1_av = sum(l['l1']) // arr_len
l2_av = sum(l['l2']) // arr_len
av = sum((l1_av, l2_av)) / 2
l['l3'] = [l1_av - av for i in range(arr_len)]
l['l4'] = [l2_av - av for i in range(arr_len)]
for i in range(arr_len):
l['l1'][i] -= av
l['l2'][i] -= av``````

## Functions to make life easier

Who wants to repeat the same action, but with different parameters? Nobody. Therefore, I wrote some helper functions to draw a graph according to the given parameters, to create a turtle. Speaking of the latter, the skulls are also entered into the general dictionary.

``````def draw(arr, t, x, mult=30):
n = len(arr)
t.up()
t.goto(-n*mult/2, 0)
for i, j in enumerate(arr):
t.goto(x+(-n*mult/2+i*mult), j)
t.down()
t.up()``````
``````def add_turtle(name, color="#000000", width=2):
t[name] = Turtle()
t[name].pencolor(color)
t[name].width(width)
t[name].hideturtle()
t[name].speed('fastest')``````

## Derived functions

At this point, the faint-hearted people who hate multi-level nesting should not read.

For the previously described common functions, you can create an infinite number of different ones.

For the derivative of the speed measurement, the structure is as follows:

``````def название(количество_повторений):
def функция_для_замера():
'''действия'''
return speed_test(функция_для_замера,
количество_повторений)``````

And the derivative for the plotting function is the same function with specific arguments.

We will check the speed of creation and the speed of execution of various types of functions.

Let’s go back to the first one. In the case of checking the speed of creating a function, function_for_sampling () will have one goal – to create a def or lambda function inside itself. We will call this function many times, and each time it will re-create the same function. In other words, the function of the second nesting level is used for multiple calls and creation of 3 nesting levels during each function. I hope you got what I meant.

I could have made it easier, but wanted to keep the structure for all derived functions.

The first two derivatives are for creating empty functions that return False. For def, I could write using return or pass, but in lambda this is not possible.

``````def test_empty_def(n):
def test(): return False

def test_empty_lambda(n):
test = lambda: False

The next two are for the same functions, but with a simple expression:

``````def test_def(n):
def test(): return sum((2, 3, 4)) ** 0.5

def test_lambda(n):
test = lambda: sum((2, 3, 4)) ** 0.5

Two more – to assess the speed of their creation + the speed of execution:

``````def test_def2(n):
def test(): return sum((2, 3, 4)) ** 0.5
test()

def test_lambda2(n):
test = lambda: sum((2, 3, 4)) ** 0.5
test()

These functions will be used in derivatives of graph_data:

``````def for_empty_func(arr_len):
graph_data(test_empty_def, test_empty_lambda, 10000, 20000, arr_len)
def for_one_eval_func(arr_len):
graph_data(test_def, test_lambda, 10000, 20000, arr_len)
def for_doing_func(arr_len):
graph_data(test_def2, test_lambda2, 10000, 20000, arr_len)``````

## Algorithm

Let’s name the window:

``title('Сравнение def и lambda функций по скорости')``

Let’s create 4 turtles for drawing a graph:

``````t = {}

Let’s define the length of the diagram at the vertices:

``arr_len = 20``

Let’s prepare the data for the graphs and build them:

``````l = {}
for i in range(5):
производная_от_graph_data(arr_len)
draw(l['l1'], t['t1'], -300)
draw(l['l2'], t['t2'], -300)
draw(l['l3'], t['t3'], 300)
draw(l['l4'], t['t4'], 300)``````

Let’s not forget to add a window close event:

``exitonclick()``
Final algorithm
``````title('Сравнение def и lambda функций по скорости')

t = {}

arr_len = 20
l = {}
for i in range(5):
for_one_eval_func(arr_len)
draw(l['l1'], t['t1'], -300)
draw(l['l2'], t['t2'], -300)
draw(l['l3'], t['t3'], 300)
draw(l['l4'], t['t4'], 300)

exitonclick()
``````
Complete code
``````from turtle import *
from time import time

def speed_test(func, n):
start = time()
for i in range(n):
func()
stop = time()
return stop - start

def test_empty_def(n):
def test(): return False

def test_empty_lambda(n):
test = lambda: False

def test_def(n):
def test(): return sum((2, 3, 4)) ** 0.5

def test_lambda(n):
test = lambda: sum((2, 3, 4)) ** 0.5

def test_def2(n):
def test(): return sum((2, 3, 4)) ** 0.5
test()

def test_lambda2(n):
test = lambda: sum((2, 3, 4)) ** 0.5
test()

t[name] = Turtle()
t[name].pencolor(color)
t[name].width(width)
t[name].hideturtle()
t[name].speed('fastest')

def draw(arr, t, x, mult=30):
n = len(arr)
t.up()
t.goto(-n*mult/2, 0)
for i, j in enumerate(arr):
t.goto(x+(-n*mult/2+i*mult), j)
t.down()
t.up()

def graph_data(func1, func2, mult1, mult2, arr_len):
l['l1'] = [func1(mult1)*mult2 for i in range(arr_len)]
l['l2'] = [func2(mult1)*mult2 for i in range(arr_len)]
l1_av = sum(l['l1']) // arr_len
l2_av = sum(l['l2']) // arr_len
av = sum((l1_av, l2_av)) / 2
l['l3'] = [l1_av - av for i in range(arr_len)]
l['l4'] = [l2_av - av for i in range(arr_len)]
for i in range(arr_len):
l['l1'][i] -= av
l['l2'][i] -= av

def for_empty_func(arr_len):
graph_data(test_empty_def, test_empty_lambda, 10000, 20000, arr_len)

def for_one_eval_func(arr_len):
graph_data(test_def, test_lambda, 10000, 20000, arr_len)

def for_doing_func(arr_len):
graph_data(test_def2, test_lambda2, 10000, 20000, arr_len)

title('Сравнение def и lambda функций по скорости')

t = {}

arr_len = 20
l = {}
for i in range(5):
for_one_eval_func(arr_len)
draw(l['l1'], t['t1'], -300)
draw(l['l2'], t['t2'], -300)
draw(l['l3'], t['t3'], 300)
draw(l['l4'], t['t4'], 300)

exitonclick()
``````

## Tests

Moving on to the main thing – which is faster? Green on the chart denotes lambda, red – def

The first test is for the speed of creating an empty (almost) function:

The second test is for the speed of creating speed with the expression: