17

最近我开始好奇,但以下虚假 python 代码的第 2 行发生了什么:

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

我开始感兴趣的原因是我正在尝试 Light Table 并试图在“foo”上放一个手表。它似乎导致 python 解释器挂起。

我认为这条线绝对没有效果并且不会引起任何错误,我是否正确?有人能解释一下口译员在这里到底做了什么吗?

4

5 回答 5

27

借助内置的dis模块,可以查看正在发生的事情:

import dis

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

dis.dis(my_fun)

dis.dis函数反汇编函数(是的,它可以自行反汇编)、方法和类。

的输出dis.dis(my_fun)是:

  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

前两个字节码正是我们需要的:foo行。

以下是这些字节码的作用:

  1. 第一个将对局部变量的引用foo推入堆栈(LOAD_FAST
  2. 第二个删除堆栈的顶部(POP_TOP

基本上,foo线没有效果。(好吧,如果foo没有定义变量,那么LOAD_FAST将抛出NameError

于 2014-01-21T14:28:31.623 回答
9

什么都没发生。它变得相当于一个毫无意义的操作查看dis输出

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 

我们可以看到它可以快速加载,foo然后什么也不做。

于 2014-01-21T14:28:19.210 回答
4

在命令行尝试一下:它只返回foo. 这并不意味着它在某些特殊情况下不会产生副作用:如果您执行以下操作:

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

即使从技术上讲我们刚刚返回了值,如果它被定义为一个属性,那么foo.prop实际上可以调用一个函数。

但通常......你不会在模块中这样做,只能在交互式控制台中。

于 2014-01-21T14:27:15.330 回答
2

foo语句是表达式语句的示例,因此在解释器遇到它时会对其进行评估。

表达式语句计算表达式列表(可能是单个表达式)。

所以foo加载,表达式被评估(它foo本身,所以不需要进一步的操作),结果立即被遗忘。

于 2014-01-21T14:35:33.807 回答
1

什么都没发生:

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

>>> baz(10, 20)
20

该声明无效。

于 2014-01-21T14:28:51.523 回答