Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python在变量超出范围时不删除它_Python - Fatal编程技术网

Python在变量超出范围时不删除它

Python在变量超出范围时不删除它,python,Python,考虑以下代码: import random class Trie: def __init__(self, children, end):

考虑以下代码:

import random                                                                   

class Trie:                                                                     
    def __init__(self, children, end):                                          
        self.children = children                                                
        self.end = end                                                          

def trie_empty():                                                               
    return Trie(dict(), False)                                                  

def trie_insert(x, t):                                                          
    if not x:                                                                   
        t.end = True                                                            
        return                                                                  
    try:                                                                        
        t2 = t.children[x[0]]                                                   
    except KeyError:                                                            
        t2 = trie_empty()                                                       
        t.children[x[0]] = t2                                                     
    trie_insert(x[1:], t2)                                                      

def fill_dict(root):                                                            
    memo = dict()                                                               
    def fill(pfx='', depth=0):                                                  
        try:                                                                    
            memo[pfx]                                                           
        except KeyError:                                                        
            pass                                                                
        else:                                                                   
            return                                                              
        if depth > 6:                                                           
            return                                                              
        for ci in range(ord('a'), ord('d') + 1):                                
            fill(pfx + chr(ci), depth + 1)                                      
        bw = None                                                               
        memo[pfx] = None, bw                                                    
    fill()                                                                      
    # del memo                                                                  

def random_word():                                                              
    l = int(random.random() * 10)                                               
    w = ''.join([chr(int(random.random() * 26) + ord('a')) for _ in range(l)])  
    return w                                                                    

def main():                                                                     
    t = trie_empty()                                                            
    for _ in range(10000):                                                      
        trie_insert(random_word(), t)                                           

    while True:                                                                 
        fill_dict(t)                                                            

if __name__ == '__main__':                                                      
    main()
当我运行它时,它会继续使用更多内存,直到我杀死它。如果我取消对del memo的注释,它将在使用恒定内存量的情况下运行。由此,我得出结论,当fill_dict返回时,局部变量memo没有被清除

这种行为对我来说真的很神秘,特别是因为基本上上述所有代码都是看到这种行为所必需的。即使是用于填充dict的完全未使用的参数也不能忽略,因为程序使用无限内存


这真令人沮丧。当然,一种现代的垃圾收集语言可以清理自己的变量,我不应该手动删除函数局部变量。当函数返回时,即使是C也可以清理堆栈。为什么Python不能在这种情况下运行?

我认为这个问题应该得到一个答案,现在在我和ProgramMan之间,我们已经找到了答案

模块级功能填充有一个内部功能填充:

此内部名称填充绑定到通过编译其内容创建的实体。该实体引用了名称备忘录,该备忘录在条目处绑定到一个新的空字典以填充目录,因此该实体本身就是一个名称备忘录

现在,闭包可以被垃圾收集,Python确实有一个垃圾收集器。但CPython特别有一个两层收集器:有一种基于引用计数的主、始终打开的收集器,然后是一个真正的标记和扫描样式的GC,它运行的频率要低得多。看到和

侧栏:引用计数收集器有什么问题? 引用计数采集器被以下周期击败:

>>> x = []
>>> x.append(x)
>>> x
[[...]]
这里x绑定到一个列表,其第一个元素是x绑定到的列表。也就是说,x[0]是x,x[0][0]是x,依此类推:

>>> x[0] is x
True
>>> x[0][0] is x
True
对于这种循环,删除x没有帮助,因为列表引用它自己。然而,我们可以做一个更有趣的循环:

>>> a = dict()
>>> b = dict()
>>> a['link-to-b'] = b
>>> b['link-to-a'] = a
>>> a
{'link-to-b': {'link-to-a': {...}}}
>>> b
{'link-to-a': {'link-to-b': {...}}}
现在,如果我们去掉其中一个链接,循环就会消失:

>>> a['link-to-b'] = None
>>> a
{'link-to-b': None}
>>> b
{'link-to-a': {'link-to-b': None}}
一切都会好起来的

回到手头的问题上来 在这种特殊情况下,fill在其外部fill dict中引用了memo实例,memo中的一个条目是:

变量bw本身是在闭包中定义的,所以memo[pfx]指闭包,或者更准确地说,指闭包中的一个实体,而闭包指的是memo,这是我们的循环引用


因此,即使当fill_dict返回时,闭包上的引用计数也没有下降到零。

我认为这个问题应该得到答案,现在我和Program man之间已经找到了答案

模块级功能填充有一个内部功能填充:

此内部名称填充绑定到通过编译其内容创建的实体。该实体引用了名称备忘录,该备忘录在条目处绑定到一个新的空字典以填充目录,因此该实体本身就是一个名称备忘录

现在,闭包可以被垃圾收集,Python确实有一个垃圾收集器。但CPython特别有一个两层收集器:有一种基于引用计数的主、始终打开的收集器,然后是一个真正的标记和扫描样式的GC,它运行的频率要低得多。看到和

侧栏:引用计数收集器有什么问题? 引用计数采集器被以下周期击败:

>>> x = []
>>> x.append(x)
>>> x
[[...]]
这里x绑定到一个列表,其第一个元素是x绑定到的列表。也就是说,x[0]是x,x[0][0]是x,依此类推:

>>> x[0] is x
True
>>> x[0][0] is x
True
对于这种循环,删除x没有帮助,因为列表引用它自己。然而,我们可以做一个更有趣的循环:

>>> a = dict()
>>> b = dict()
>>> a['link-to-b'] = b
>>> b['link-to-a'] = a
>>> a
{'link-to-b': {'link-to-a': {...}}}
>>> b
{'link-to-a': {'link-to-b': {...}}}
现在,如果我们去掉其中一个链接,循环就会消失:

>>> a['link-to-b'] = None
>>> a
{'link-to-b': None}
>>> b
{'link-to-a': {'link-to-b': None}}
一切都会好起来的

回到手头的问题上来 在这种特殊情况下,fill在其外部fill dict中引用了memo实例,memo中的一个条目是:

变量bw本身是在闭包中定义的,所以memo[pfx]指闭包,或者更准确地说,指闭包中的一个实体,而闭包指的是memo,这是我们的循环引用


因此,即使当fill_dict返回时,闭包上的引用计数也没有下降到零。

为什么trie_为空,trie_插入常规函数而不是方法?我怀疑这是因为您使用的是闭包填充,闭包的特殊之处在于它们记住了调用它们的上下文。假设它使用memo,它可能会保留一个句柄,这样它就不会超出范围。@chepner因为我不太习惯OOP,而且它不会影响我看到的奇怪行为。fill\u dict中的fill绑定到通过调用fill\u dict创建的闭包,这个闭包使memo保持活动状态。不清楚的是,当fill_dict返回时,是什么使闭包本身保持活动状态。如果root有一个对fill的引用,或者fill中有一个活跃的东西,这就是为什么,但它没有。哦,我想我知道,memo有一个对bw的引用,bw在fill中,fill有一个对memo的引用,所以它是一个循环re
引用和它永远不会被清除为什么trie_为空和trie_插入正则函数而不是方法?我怀疑这是因为您使用的是闭包填充,闭包的特殊之处在于它们记住调用它们的上下文。假设它使用memo,它可能会保留一个句柄,这样它就不会超出范围。@chepner因为我不太习惯OOP,而且它不会影响我看到的奇怪行为。fill\u dict中的fill绑定到通过调用fill\u dict创建的闭包,这个闭包使memo保持活动状态。不清楚的是,当fill_dict返回时,是什么使闭包本身保持活动状态。如果root有一个对fill的引用,或者fill里面有一个活生生的东西,那就是为什么,但它没有。哦,我想我知道,memo有一个对bw的引用,bw在fill中,fill有一个对memo的引用,所以它是一个循环引用,它从来没有被清理过!循环引用!”然后跑向群山:-灵巧的写作-我已经到了“结束”的地步!循环引用!”然后向山跑去