2017-06-21 51 views
1

我需要用列表初始化2d數組。
例如2X3陣列:[[0,0,0], [0,0,0]]在Python中初始化2d列表提供了值之間的鏈接(相同地址)

首先嚐試:

In: a1 = [[0]*3]*2 
In: a1[0][0] = 100 
In: a1 
Out: [[100,0,0], [100,0,0]] 

這很奇怪。所以我檢查:

In: a1 = [[0]*3]*2 
In: id(a1[0][0]) 
Out: 4518461984 
In: id(a1[1][0]) 
Out: 4518461984 

相同的地址。

第二次嘗試:

In: a2 =[[0]*3 for i in range(2)] 
In: a2[0][0] = 100 
In: a2 
Out: [[100, 0, 0], [0, 0, 0]] 

權。

讓我再次檢查存儲器地址:

In: a2 =[[0]*3 for i in range(2)] 
In: id(a2[0][0]) 
Out: 4518461984 
In: id(a2[1][0]) 
Out: 4518461984 

好了,奇怪。同樣的地址了。我預計不同的地址。我最初的猜測是返回的地址是指向值的指針地址。那我該如何檢索插槽的地址?

有沒有人可以解釋導致此行爲的Python的工作原理?在Python中,我認爲很難知道哪個是指針,哪個是價值。

+0

我讀過它,但它有所不同,因爲它是根據使用*或範圍生成副本的時候。 –

+0

@Coldspeed的評論解決了我的問題。 '作爲補充說明,請注意,如果使用帶有可變結構的*,那些引用也會被重用。 - Coldspeed' –

回答

1

在Python中,表達式[v] * n相當於「將對v的引用附加到外部列表n次」。

這始終是罰款f是文字:

a = [1] * 4 
id(a[0]) == id(a[2]) # True 

a[0] = 15     
print(a)    # a == [15, 1, 1, 1] 

然而,同樣的機制適用於f是一個可變的。對f的引用被插入n次。

a = [ [1, 2, 3] ] * 3 

如果你再修改的a任何元素,所有的人也將被修改,因爲它們是同一個列表中的所有引用。

a[0][0] = 2 
print(a)  # [[2, 2, 3], [2, 2, 3], [2, 2, 3]] 

你可以通過閱讀common sequence operations的文檔詳細瞭解此行爲。

創建多維表的建議方法是:

n = 5 
mda = [[0] * 3 for _ in range(5)] 

這工作,因爲在一個新的列表實例被創建,然後附加到外部列表中的每次循環。

2

您正在比較列表中值的內存地址而不是列表的地址。

您列出的內存地址不同:

>>> a2 =[[0]*3 for i in range(2)] 
>>> id(a2[0]) == id(a2[1]) # compare memory addresses of the sublists 
False 

但在你的第一個例子中的「子」列表是相同的:

>>> a1 = [[0]*3]*2  
>>> id(a1[0]) == id(a1[1]) 
True 

的問題,爲什麼值具有相同的內存ADRESS是更復雜:

  • Python重用整數-5到255(CPython at least)所以0將始終具有相同的內存地址。

    >>> a = 0 
    >>> b = 0 
    >>> a is b 
    True 
    
  • 10000文字數字具有相同的存儲器地址,如果它們在相同的塊中定義(在相同的功能使用 - 說不定也相同模塊 - 或在相同的「線」,當不是在一個功能) 。

    >>> a = 5000 
    >>> b = 5000 
    >>> a is b # different "lines" and not in a function! 
    False 
    
    >>> a, b = 5000, 5000 
    >>> a is b # defined on the same "line" 
    True 
    
  • 當你乘一個list引用被重用。在這種情況下,它並不重要,因爲它是一個文字編號,所以引用總是被重用。但如果它不是可能是重要的文字數量:

    >>> l = [int('1000')]*3 
    >>> l[0] is l[1] 
    True 
    
    >>> l = [int('1000') for _ in range(3)] 
    >>> l[0] is l[1] 
    False 
    

在你的情況,你定義在同一行的數量,這是一個小整數所以他們將始終具有相同的內存地址。

+2

作爲補充說明,請注意,如果使用帶有可變結構的*,那些引用也會被重用。 –

+0

@折速這是正確的,但是如果你比較不同的子列表,那隻會影響每個子列表。爲什麼第一個子列表中的第一個數字與第二個子列表中的第一個數字具有相同的id是因爲「小整數高速緩存」。 – MSeifert

相關問題