繁体   English   中英

为什么 python memory 分配会这样?

[英]Why does python memory allocation behave like this?

考虑以下代码,该代码用于查找所有带有 n 个括号的有效括号位置。

def paren(n):
    ans = []
    def helper(string, left, right,n,foo):
        if len(string)==2*n:
            ans.append(string)
        if left > 0:
            helper(string+'(', left-1,right,n)
        if right > left:
            helper(string+')', left,right-1,n)
    helper('',n,n,n)

如果我们添加一个列表(在函数中没有实际用途),我们得到

def paren(n):
    ans = []
    def helper(string, left, right,n,foo):
        print(hex(id(foo)), foo)
        if len(string)==2*n:
            ans.append(string)
        if left > 0:
            helper(string+'(', left-1,right,n,[])
        if right > left:
            helper(string+')', left,right-1,n,[])
    helper('',n,n,n,[])
    
paren(2)

OUTPUT:

0x2e5e2446288 []
0x2e5e28e3508 []
0x2e5e28e3688 []
0x2e5e26036c8 []
0x2e5e27bafc8 []
0x2e5e28e3688 []
0x2e5e26036c8 []
0x2e5e27bafc8 []

而如果我们每次都明确地传递 foo 那么我们得到

def paren(n):
    ans = []
    def helper(string, left, right,n,foo):
        print(hex(id(foo)), foo)
        if len(string)==2*n:
            ans.append(string)
        if left > 0:
            helper(string+'(', left-1,right,n,foo)
        if right > left:
            helper(string+')', left,right-1,n,foo)
    helper('',n,n,n,[])
    
paren(2)

OUTPUT:

0x1c2cfec6288 []
0x1c2cfec6288 []
0x1c2cfec6288 []
0x1c2cfec6288 []
0x1c2cfec6288 []
0x1c2cfec6288 []
0x1c2cfec6288 []
0x1c2cfec6288 []

在第一种情况下,我们在 memory 中得到不同的 object,为什么与第二种情况相比,我认为这与我们创建一个新列表而不是传递 ZC1C425268E687385D1AB14A507C 参数有关?

然而,当我们向 foo 添加一些东西时,我们会得到与第一种情况相同的行为:

def paren(n):
    ans = []
    def helper(string, left, right,n,foo):
        print(hex(id(foo)), foo)
        if len(string)==2*n:
            ans.append(string)
        if left > 0:
            helper(string+'(', left-1,right,n,foo+['bar'])
        if right > left:
            helper(string+')', left,right-1,n,foo+['bar'])
    helper('',n,n,n,[])
    
paren(2)

OUTPUT:

0x269572e6288 []
0x26959283548 ['bar']
0x26957363688 ['bar', 'bar']
0x2695925ae88 ['bar', 'bar', 'bar']
0x26957363408 ['bar', 'bar', 'bar', 'bar']
0x2695925ae88 ['bar', 'bar']
0x26957363408 ['bar', 'bar', 'bar']
0x269592833c8 ['bar', 'bar', 'bar', 'bar']

但奇怪的是,如果我们为 foo 传递一些 int,我将取 5 进行演示,我们得到:

def paren(n):
    ans = []
    def helper(string, left, right,n,foo):
        print(hex(id(foo)), foo)
        if len(string)==2*n:
            ans.append(string)
        if left > 0:
            helper(string+'(', left-1,right,n,5)
        if right > left:
            helper(string+')', left,right-1,n,5)
    helper('',n,n,n,5)
    
paren(2)

OUTPUT:

0x7ffef47293c0 5
0x7ffef47293c0 5
0x7ffef47293c0 5
0x7ffef47293c0 5
0x7ffef47293c0 5
0x7ffef47293c0 5
0x7ffef47293c0 5
0x7ffef47293c0 5

即 memory 中的同一点。

但是,如果我用更大的 int 替换上述代码中的 5,例如 2550,我会得到以下结果:

0x2519f6d4790 2550
0x2519f9ec6f0 2550
0x2519f9ec6f0 2550
0x2519f9ec6f0 2550
0x2519f9ec6f0 2550
0x2519f9ec6f0 2550
0x2519f9ec6f0 2550
0x2519f9ec6f0 2550

所以最初它存储在不同的 memory 地址,但每个后续调用都在同一个地址。 为什么这与 foo=5 的情况不同,这里发生了什么?

同样在 memory 地址在调用之间发生变化的示例中,我确实看到相同的 memory 地址在多个场合使用,例如:

...
0x2695925ae88 ['bar', 'bar', 'bar']
...
0x2695925ae88 ['bar', 'bar']
...

为什么会这样? 一旦旧变量不再在递归调用堆栈中,python 是否使用以前使用的 memory 地址来存储新变量?

我对这些行为真的很模糊,所以如果有人能帮助我,那就太好了!

我听说过诸如按引用传递和按值传递之类的事情,但我不太确定它们的含义以及它是否与此 python 示例有关。

谢谢你。

第一个代码:调用堆栈保留对每个foo的引用,因此您在 memory 中有许多列表,每个列表都有一个唯一的 ID。

第二个代码:您将相同的列表(最初为空)传递给每个递归调用。

第三个代码:Cpython,作为特定于实现的优化,缓存小的int常量以供重用

第四个代码 Cpython不会缓存大(即大于 256),因此每次出现 2550 都会创建一个新的int object。

我将尝试用通用的解释向您解释这种行为。

Python 区分参考数据类型和原始数据类型。 引用数据类型将 memory 中的引用保存为存储值,而不是它们自身的值。 另一方面,原始(或值)数据类型保存值本身。

如果你将一个数组传递给一个方法,它每次都会创建这个数组的一个新实例。 因此,执行some_function([])会生成一个新数组并将其传递给 function。 这意味着调用some_function([])然后再次调用 some_function([] some_function([])将在每次调用时创建一个数组。 但是,如果您创建一个像foo = []这样的数组,那么 foo 将引用该数组并调用some_function(foo)然后some_function(foo)将在该数组上执行some_function

对于 float、int、boolean 之类的值不会发生这种情况,但对于对象和 arrays 之类的值会发生这种情况。

可以通过以下关键字进行后续研究:引用数据类型、值数据类型、内置类型。

我希望我的回答有助于理解所述问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM