我用递归定义了下面的阶乘函数:

def factorial(n):
    if n == 0:
        return n
    else:
        return n*factorial(n-1)

然后,我定义了下面的函数来返回调用factorial函数时引发RecursionError的最小值.(我已经为此导入了sys模块)

def test_recursion(n):
    sys.setrecursionlimit(n)
    num = 0
    while True:
        try:
            x = factorial(num)
            num += 1
        except:
            return num

我知道这个函数有点误导,因为调用test_recursion函数本身占用了调用堆栈中的一个插槽.

现在,如果我创建列表l1如下:

l1 = []
for i in [10,11,12]:
    l1.append(test_recursion(i))

l2被认为是等价的列表,通过使用列表理解

l2 = [test_recursion(i) for i in [10,11,12]]

现在,print(l1, l2, sep = "\n"给出以下输出:

[7,8,9]
[6,7,8]

为什么会发生这种情况?字典和集合解释也会发生这种情况.

是不是理解在后台调用某个函数,占用了堆栈中的一个插槽?理解的内在实现如何解释这一点?

推荐答案

是的在Python 3.10.13下,使用以下函数:

def test1():
    l1 = []
    for i in [10,11,12]:
        l1.append(test_recursion(i))
    return l1

def test2():
    l2 = [test_recursion(i) for i in [10,11,12]]
    return l2

使用第一个片段(dis.dis(test1))上的disassembler:

 20           0 BUILD_LIST               0
              2 STORE_FAST               0 (l1)

 21           4 LOAD_CONST               1 ((10, 11, 12))
              6 GET_ITER
        >>    8 FOR_ITER                 9 (to 28)
             10 STORE_FAST               1 (i)

 22          12 LOAD_FAST                0 (l1)
             14 LOAD_METHOD              0 (append)
             16 LOAD_GLOBAL              1 (test_recursion)
             18 LOAD_FAST                1 (i)
             20 CALL_FUNCTION            1
             22 CALL_METHOD              1
             24 POP_TOP
             26 JUMP_ABSOLUTE            4 (to 8)

 23     >>   28 LOAD_FAST                0 (l1)
             30 RETURN_VALUE

在第二个片段中:

 26           0 LOAD_CONST               1 (<code object <listcomp> at 0x1048a0d40, file "/Users/amadan/tmp/a.py", line 26>)
              2 LOAD_CONST               2 ('test2.<locals>.<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_CONST               3 ((10, 11, 12))
              8 GET_ITER
             10 CALL_FUNCTION            1
             12 STORE_FAST               0 (l2)

 27          14 LOAD_FAST                0 (l2)
             16 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x1048a0d40, file "/Users/amadan/tmp/a.py", line 26>:
 26           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                 6 (to 18)
              6 STORE_FAST               1 (i)
              8 LOAD_GLOBAL              0 (test_recursion)
             10 LOAD_FAST                1 (i)
             12 CALL_FUNCTION            1
             14 LIST_APPEND              2
             16 JUMP_ABSOLUTE            2 (to 4)
        >>   18 RETURN_VALUE

所以你可以看到理解被当作一个函数来对待.我相信它的目的是将理解中创建的变量隔离在它们自己的作用域中.例如:

x = "original value"
[x for x in ["new value"]]
print(x)     # original value

vs

x = "original value"
for x in ["new value"]:
    pass
print(x)     # new value

Python相关问答推荐

运行Python脚本时,用作命令行参数的SON文本

Telethon加入私有频道

两个pandas的平均值按元素的结果串接元素.为什么?

在Python argparse包中添加formatter_class MetavarTypeHelpFormatter时, - help不再工作""""

形状弃用警告与组合多边形和多边形如何解决

在ubuntu上安装dlib时出错

Plotly Dash Creating Interactive Graph下拉列表

将pandas导出到CSV数据,但在此之前,将日期按最小到最大排序

如何在FastAPI中为我上传的json文件提供索引ID?

可以bcrypts AES—256 GCM加密损坏ZIP文件吗?

如何在达到end_time时自动将状态字段从1更改为0

如何使用两个关键函数来排序一个多索引框架?

ruamel.yaml dump:如何阻止map标量值被移动到一个新的缩进行?

提高算法效率的策略?

polars:有效的方法来应用函数过滤列的字符串

如何在FastAPI中替换Pydantic的constr,以便在BaseModel之外使用?'

我怎么才能用拉夫分拣呢?

为什么我的scipy.optimize.minimize(method=";newton-cg";)函数停留在局部最大值上?

时长超过24小时如何从Excel导入时长数据

在不中断格式的情况下在文件的特定部分插入XML标签