Performance of functions with and without creation of local variables


Despite the simplicity of this question, I could not find an answer for it on the Internet.

Is there any structural / performatic difference between the two functions defined below?

def F(x):

  Output = x + 1

  return Output
def F(x):

    return x + 1
asked by anonymous 17.12.2018 / 22:45

4 answers


Just to complement Maniero's response:

You can use the module dis (Disassembler) to check the difference between the generated bytecodes .


from dis import dis

def exemplo_1(x):
    output = x + 1
    return output

def exemplo_2(x):
    return x + 1

print('>>> dis(exemplo_1)')

print('-' * 60)

print('>>> dis(exemplo_2)')
dis(exemplo_2) with the code running

The output (in Python 3.7.1) is:

>>> dis(exemplo_1)
  4           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (1)
              4 BINARY_ADD
              6 STORE_FAST               1 (output)

  5           8 LOAD_FAST                1 (output)
             10 RETURN_VALUE
>>> dis(exemplo_2)
  8           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (1)
              4 BINARY_ADD
              6 RETURN_VALUE

It is a good tool to test simple cases like this, even though you do not fully understand the output, you can already see that exemplo_1 allocates memory to ouput .

18.12.2018 / 12:24

In general I can say that it is zero. The result should be the same, this can not be change. The performance is also not meant to be different, but nothing guarantees. This kind of thing depends on implementation to determine if any is faster. There is not just one Python. All implementations must have the same result, but the performance characteristics of each one is their problem.

That said, I am against creating variables without necessity. Variables must exist for two reasons:

  • Needs an intermediate result to be saved somewhere for later use in more than one place , so it would be bad or would produce erroneous results if you have to get this value more than once; or it depends on the order the information will be acquired and used and so the value guard is important
  • You need to better document what you are doing that is not obvious when you read, so a variable with an excellent name is used to indicate what that result is.

In general I see programmers creating the variable because they do not know what they can do without it. The programmer only plays cake recipe and does not understand What is a variable? . And I've seen some justifying that it would be for readability, but the name of the variable used is completely meaningless, which shows that it's a lie, for example this case, artificial, I know, the name means nothing. Indicate that it is an output? Dããã! This does not make the code more readable. This is a case that, for all intents and purposes, although it works, to always give the same result from a stylistic point of view, and this has a little taste, I consider the first code to be an error. Another code context next to this but it makes sense to have a variable to document so I think differently.

The fernandosavio response shows that in the main Python implementation a different bytecode is generated if you use the variable, which I would classify as unfortunate since it has no utility. But it does not surprise me, Python is not a proper language when concern is performance. If you need this use another language.

Actually there could be some optimization, and someday might be, so the hkotsubo response that shows that this implementation really is slower when using the variable, but it is a transient situation.

Reinforcement should look for the most readable option, if the use of the variable brings more readability should use it as a priority, which is not even the case of the example question. Python is mostly a script language, so any concern with micro-optimization in it does not make sense. The example should not use variable because besides being faster it is more readable to return a value soon, a variable that adds nothing to noise.

17.12.2018 / 23:18

Complementing the other responses, a simple way to compare performance is to use module timeit . .

import timeit

def exemplo_1(x):
    output = x + 1
    return output

def exemplo_2(x):
    return x + 1

n = 100000000
rep = 5
print(timeit.repeat("exemplo_1(1)", 'from __main__ import exemplo_1', number = n, repeat = rep))
print(timeit.repeat("exemplo_2(1)", 'from __main__ import exemplo_2', number = n, repeat = rep))

In the above example I'm calling each function 100 million times (and repeating each cycle 100 million times 5 times). The return is a list with the times of each of the 5 cycles:

[10.230189208560486, 10.76496154874702, 10.183613784861148, 9.914715879252743, 9.953630417515548]
[9.250180609985641, 9.20510965178623, 9.140656262847259, 9.346281658065251, 9.511226614071674]

Time can vary with each run as it depends on a number of variables (such as your hardware, whether there were other processes running on the machine, etc.), so you will not necessarily have the same results as me. But notice that the second version (without allocating the variable output ) is slightly faster (about 1 second of difference, more or less).

But that was for 100 million runs. When I changed n to 1 million, the difference between the first and second versions fell to about 1 / second . And for smaller programs (where the function will be executed a few times) will make even less difference, to the point of being irrelevant (for% with equal% 100, for example, I got differences in the house of 1 microsecond - the sixth decimal place of fractions of second).

Honestly, unless your code really needs to run hundreds of millions of times in a row and the performance is extremely critical, you should not worry about that. The main concern should be the creation of readable code and the use of variables where it makes sense, as explained well in the Maniero's answer .

And if your system is experiencing performance issues, it certainly will not be in these functions. In this case, you should do specific performance tests to find out where the bottlenecks are.

18.12.2018 / 12:59

There is always the% time function that I use in jupyter, but in this case the time difference was so low that it did not register the difference: follow another example of connecting to an API, which recorded the time.



Ipython Magic

18.12.2018 / 13:42