Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is there a performance difference between omitting and including a return statement within a python function?

Assuming we have a function that updates a bunch of internal values within a class like so:

class MyClass:
    def __init__():
        self.counter = 0
        self.condition_1 = True
        self.condition_2 = False
    def update():
        if self.condition_1:
            if self.condition_2:
                self.counter += 2
                # return or not?
            else:
                self.counter += 1
                # return or not?
        else:
            self.counter -= 1
            # return or not?

Would the update function be executed faster with or without a return statement within it (after updating variables)? Or would it be 100% the same? (unlikely for me)

I know this sounds like a trivial/dumb question to ask without context, but consider that this function is being called repeatedly thousands of times so slight increase in performance within the function can have a large impact on how fast the whole program takes to execute.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

In my real program, the conditions within the update function are very complex and more nested; the program processes a lot of data as well.

>Solution :

You can look at the produced bytecode to answer this:

With explicit returns:

  4           0 LOAD_CONST               1 (0)
              2 STORE_FAST               0 (counter)
  5           4 LOAD_FAST                0 (counter)
              6 LOAD_CONST               1 (0)
              8 COMPARE_OP               2 (==)
             10 POP_JUMP_IF_FALSE       22 (to 44)
  6          12 LOAD_FAST                0 (counter)
             14 LOAD_CONST               2 (1)
             16 COMPARE_OP               2 (==)
             18 POP_JUMP_IF_FALSE       16 (to 32)
  7          20 LOAD_FAST                0 (counter)
             22 LOAD_CONST               3 (2)
             24 INPLACE_ADD
             26 STORE_FAST               0 (counter)
  8          28 LOAD_CONST               0 (None)
             30 RETURN_VALUE
 10     >>   32 LOAD_FAST                0 (counter)
             34 LOAD_CONST               2 (1)
             36 INPLACE_ADD
             38 STORE_FAST               0 (counter)
 11          40 LOAD_CONST               0 (None)
             42 RETURN_VALUE
 13     >>   44 LOAD_FAST                0 (counter)
             46 LOAD_CONST               2 (1)
             48 INPLACE_SUBTRACT
             50 STORE_FAST               0 (counter)
 14          52 LOAD_CONST               0 (None)
             54 RETURN_VALUE

Without explicit returns:

  4           0 LOAD_CONST               1 (0)
              2 STORE_FAST               0 (counter)
  5           4 LOAD_FAST                0 (counter)
              6 LOAD_CONST               1 (0)
              8 COMPARE_OP               2 (==)
             10 POP_JUMP_IF_FALSE       22 (to 44)
  6          12 LOAD_FAST                0 (counter)
             14 LOAD_CONST               2 (1)
             16 COMPARE_OP               2 (==)
             18 POP_JUMP_IF_FALSE       16 (to 32)
  7          20 LOAD_FAST                0 (counter)
             22 LOAD_CONST               3 (2)
             24 INPLACE_ADD
             26 STORE_FAST               0 (counter)
             28 LOAD_CONST               0 (None)
             30 RETURN_VALUE
 10     >>   32 LOAD_FAST                0 (counter)
             34 LOAD_CONST               2 (1)
             36 INPLACE_ADD
             38 STORE_FAST               0 (counter)
             40 LOAD_CONST               0 (None)
             42 RETURN_VALUE
 13     >>   44 LOAD_FAST                0 (counter)
             46 LOAD_CONST               2 (1)
             48 INPLACE_SUBTRACT
             50 STORE_FAST               0 (counter)
             52 LOAD_CONST               0 (None)
             54 RETURN_VALUE

Although it’s hard to see manually, they result in identical bytecode. The only difference is the loading of None is associated with a line with the explicit return version.


Test code:

def update():
    counter = 0
    if counter == 0:
        if counter == 1:
            counter += 2

        else:
            counter += 1

    else:
        counter -= 1

dis(update)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading