17

Recently I became curious about but what happens in line 2 of the following bogus python code:

def my_fun(foo,bar):
    foo
    return foo + bar

The reason I became interested is that I'm trying Light Table and tried to put a watch on "foo." It appeared to cause the python interpreter to hang.

Am I correct in thinking that this line has absolutely no effect and does not cause any sort of error? Can someone explain what the interpreter does exactly here?

foobarbecue
  • 6,780
  • 4
  • 28
  • 54

5 Answers5

27

One can look at what is happening with a little help from the built-in dis module:

import dis

def my_fun(foo,bar):
    foo
    return foo + bar

dis.dis(my_fun)

The dis.dis function disassembles functions (yep, it can disassemble itself), methods, and classes.

The output of dis.dis(my_fun) is:

  4           0 LOAD_FAST                0 (foo)
              3 POP_TOP

  5           4 LOAD_FAST                0 (foo)
              7 LOAD_FAST                1 (bar)
             10 BINARY_ADD
             11 RETURN_VALUE

The first two bytecodes are exactly what we need: the foo line.

Here's what these bytecodes do:

  1. The first one pushes a reference to a local variable foo onto the stack (LOAD_FAST)
  2. The second one removes the top of the stack (POP_TOP)

Basically, foo line has no effect. (well, if foo variable is not defined then LOAD_FAST will throw the NameError)

Nigel Tufnel
  • 11,146
  • 4
  • 35
  • 31
9

Nothing happens. It becomes equivalent to a pointless operation Looking at the dis output

In [3]: dis.dis(my_fun)
  2           0 LOAD_FAST                0 (foo)
              3 POP_TOP             

  3           4 LOAD_FAST                0 (foo)
              7 LOAD_FAST                1 (bar)
             10 BINARY_ADD          
             11 RETURN_VALUE 

We can see that it does the load fast for foo then does nothing with it.

Jakob Bowyer
  • 33,878
  • 8
  • 76
  • 91
4

Try it at the command line: it just returns the value in foo. This doesn't mean it can't have side effects in some special cases: if you do something like:

def my_fun(foo, bar):
    foo.prop
    return foo.func(bar)

even though technically we have just returned the value, if it's defined as a property then foo.prop can actually call a function.

But normally... you wouldn't do this in modules, only in an interactive console.

Corley Brigman
  • 11,633
  • 5
  • 33
  • 40
2

The foo statement is an example of expression statement, so it gets evaluated when the interpreter meets it.

An expression statement evaluates the expression list (which may be a single expression).

So foo is loaded, the expression is evaluated (which is foo itself, so no further actions are needed) and the result is forgotten immediately.

Danstahr
  • 4,190
  • 22
  • 38
1

Nothing happens:

>>> def baz(foo, bar):
    foo
    return bar

>>> baz(10, 20)
20

The statement has no effect.

Games Brainiac
  • 80,178
  • 33
  • 141
  • 199
  • 3
    Although your conclusion is correct, your argument is bogus. Just because it does nothing in one case that you found, doesn't mean it does nothing in all cases. – Cruncher Jan 21 '14 at 18:53