【问题标题】:Recursion at exec() level with globalsexec() 级别的递归与全局变量
【发布时间】:2016-11-04 23:07:39
【问题描述】:

在偶然发现this question 之后,我一直在玩弄 exec() 以更好地了解它是如何工作的。我试图让脚本的这种可憎性增加全局变量,读取自身,并使用新的全局值调用 exec 直到满足递归限制。我能想到的最好的方法是让一个文件声明全局,然后调用下一个文件(完全重复减去变量声明),然后递归调用自身。这是第一个的代码:

# recurse.py

def func():
    global x
    x += 1
    with open('recurse2.py', 'r') as f:    
        try:
            exec(f.read(), {'x': x})
        except RecursionError:
            print('maximum recursion depth reached at', x)

x = 0
func()

这是它执行的文件,它将自行执行:

# recurse2.py

def func():
    global x
    x += 1
    with open('recurse2.py', 'r') as f:    
        try:
            exec(f.read(), {'x': x})
        except RecursionError:
            print('maximum recursion depth reached at', x)

func()

只有一个文件可以达到同样的效果吗?

【问题讨论】:

    标签: python python-3.x recursion global-variables


    【解决方案1】:

    你可以这样做:

    # recurse.py
    
    def func():
        global x
        x += 1
        with open('recurse.py', 'r') as f:    
            try:
                exec(f.read(), {'x': x})
            except RuntimeError:
                print('maximum recursion depth reached at', x)
    
    try:
        x
    except NameError:
        x = 0
    func()
    

    您最初示例的问题并不是exec 所特有的。只是程序本身在调用func 之前将x 设置为零。所以传入x 的起始值没有任何效果:您正在执行的代码无论如何都会设置一个新值x。在这个新版本中,try/except 块会在将名称初始化为零之前测试名称是否已经存在。

    (我在这里使用了 RuntimeError,因为我没有引入 RecursionError 的 Python 3.5,但它应该与 RecursionError 相同。)

    【讨论】:

    • 在我的系统上,它不会因为递归深度而失败,它会失败并显示:OSError: [Errno 24] Too many open files: 'recurse.py'(或 Python 2 中的 IOError) - - 我意识到这对于每个系统都是不同的,但 IOError 是可以预防的。
    【解决方案2】:

    @BrenBarn 出色解决方案的一个变体,由于打开的文件过多而失败并出现 RuntimeError(@ ~ 500 次递归)而不是 IOError(@ ~ 256 次递归):

    #recurse.py

    def func():
        global x
        x += 1
        with open('recurse.py') as source:
            string = source.read()
        try:
            exec(string, {'x': x})
        except RuntimeError:
            print('maximum recursion depth reached at', x)
    
    try:
        x
    except NameError:
        x = 0
    
    func()
    

    但是,您也可以根据需要扩展递归堆栈 (sys.setrecursionlimit()) 和/或打开文件限制 (ulimit -n)。

    【讨论】:

    • 啊,我没有注意到潜在的 IOError 问题,因为我过去提高了打开文件的限制。好点子!
    猜你喜欢
    • 2022-01-22
    • 2015-03-08
    • 1970-01-01
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多