Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: encapsulation in frequently called function

I have this Python 3 pseudo-code:

def f1():
    a, b, c, d, e, f = some_other_fn()
    if (condition):
        f2(a, b, c, d, e, f)

def f2(a, b, c, d, e, f):
    complex_set_of_operations_with(a, b, c, d, e, f)

for i in range(1000):
    f(1)

Now, I am kind of annoyed at the long signature and repetition in f2() and would like to encapsulate that into f1():

def f1():
    def f2():
        complex_set_of_operations_with(a, b, c, d, e, f)

    a, b, c, d, e, f = some_other_fn()
    if (condition):
        f2()

for i in range(1000):
    f(1)

Now, my question is: if I run f1() a thousand times, does the interpreter have to parse f2() a thousand times or is it smart enough to create a reusable reference?

like image 837
user3758232 Avatar asked Oct 17 '22 23:10

user3758232


1 Answers

Let's have a look (using Python 3.5 that I happen to have at hand). We will use the dis module to disassemble the function and inspect its bytecode:

>>> def f1():
...     def f2():
...         complex_set_of_operations_with(a, b, c, d, e, f)
...     a, b, c, d, e, f = some_other_fn()
...     if (condition):
...         f2()
... 
>>> import dis
>>> dis.dis(f1)
  2           0 LOAD_CLOSURE             0 (a)
              3 LOAD_CLOSURE             1 (b)
              6 LOAD_CLOSURE             2 (c)
              9 LOAD_CLOSURE             3 (d)
             12 LOAD_CLOSURE             4 (e)
             15 LOAD_CLOSURE             5 (f)
             18 BUILD_TUPLE              6
             21 LOAD_CONST               1 (<code object f2 at 0x7f5d58589e40, file "<stdin>", line 2>)
             24 LOAD_CONST               2 ('f1.<locals>.f2')
             27 MAKE_CLOSURE             0
             30 STORE_FAST               0 (f2)
             ...  # the rest is omitted for brevity

In runtime, the Python interpreter interprets these primitive bytecode instructions one by one. These instructions are explained in the documentation.

As the last four instructions from the example above suggest, Python indeed builds the internal function every time (and stores it under the name f2), but it appears to do so efficiently by loading a pre-compiled constant code object of f2 (the 21 LOAD_CONST) line, i.e. it does not compile the f2's body over and over again.

like image 112
plamut Avatar answered Nov 03 '22 05:11

plamut