문제

파이썬에서 목록 목록을 만들어야 했으므로 다음을 입력했습니다.

myList = [[1] * 4] * 3

목록은 다음과 같습니다.

[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]  

그런 다음 가장 안쪽 값 중 하나를 변경했습니다.

myList[0][0] = 5

이제 내 목록은 다음과 같습니다.

[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]  

내가 원하거나 기대했던 것이 아닙니다. 누군가 무슨 일이 일어나고 있는지, 어떻게 돌아 다니는 지 설명해 주시겠습니까?

도움이 되었습니까?

해결책

당신이 쓸 때 [x]*3 당신은 본질적으로 목록을 얻습니다 [x, x, x]. 즉, 동일하게 3 개의 참조가있는 목록 x. 그런 다음이 싱글을 수정하십시오 x 그것은 세 가지 참조를 통해 볼 수 있습니다.

이를 해결하려면 각 위치에서 새 목록을 작성해야합니다. 그것을하는 한 가지 방법입니다

[[1]*4 for _ in range(3)]

재평가 할 것입니다 [1]*4 매번 한 번 평가하고 1 목록에 3 개의 참조를 작성하는 대신 매번.


왜 그런지 궁금 할 것입니다 * 목록 이해력이있는 방식으로 독립적 인 대상을 만들 수는 없습니다. 곱셈 연산자 때문입니다 * 표현을 보지 않고 개체에서 작동합니다. 당신이 사용할 때 * 번식하다 [[1] * 4] 3, * 1 요소 목록 만 볼 수 있습니다 [[1] * 4] 가 아니라 평가합니다 [[1] * 4 표현식 텍스트. * 그 요소의 사본을 만드는 방법, 재평가 방법을 모른다 [[1] * 4], 그리고 당신이 사본을 원한다는 것을 알지 못하며 일반적으로 요소를 복사 할 방법조차 없을 수도 있습니다.

유일한 옵션 * Has는 새로운 하위 목록을 만드는 대신 기존 하위 목록을 새로운 언급하는 것입니다. 다른 것은 일관성이 없거나 기본 언어 설계 결정의 주요 재 설계가 필요합니다.

대조적으로, 목록 이해력은 모든 반복에서 요소 표현식을 재평가합니다. [[1] * 4 for n in range(3)] 재평가 [1] * 4 같은 이유로 매번 [x**2 for x in range(3)] 재평가 x**2 매번. 모든 평가 [1] * 4 새 목록을 생성하므로 목록 이해력이 원하는 것을 수행합니다.

우연히 [1] * 4 또한 요소를 복사하지 않습니다 [1], 그러나 정수는 불변이기 때문에 그것은 중요하지 않습니다. 당신은 같은 일을 할 수 없습니다 1.value = 2 그리고 1을 2로 바꿉니다.

다른 팁

size = 3
matrix_surprise = [[0] * size] * size
matrix = [[0]*size for i in range(size)]

Frames and Objects

라이브 파이썬 튜터 시각화

사실, 이것은 정확히 당신이 기대하는 것입니다. 여기서 일어나는 일을 분해합시다.

당신은 쓰기

lst = [[1] * 4] * 3

이것은 다음과 같습니다.

lst1 = [1]*4
lst = [lst1]*3

이것은 의미합니다 lst 3 개의 요소가 모두 가리키는 목록입니다 lst1. 이것은 다음 두 줄이 동일하다는 것을 의미합니다.

lst[0][0] = 5
lst1[0] = 5

처럼 lst[0] 아무것도 아닙니다 lst1.

원하는 동작을 얻으려면 목록 이해력을 사용할 수 있습니다.

lst = [ [1]*4 for n in xrange(3) ]

이 경우, 표현식은 각 N에 대해 재평가되어 다른 목록을 초래합니다.

[[1] * 4] * 3

또는:

[[1, 1, 1, 1]] * 3

내부를 참조하는 목록을 만듭니다 [1,1,1,1] 3 번 - 내부 목록의 세 가지 사본이 아니므로 목록을 수정할 때마다 (모든 위치에서) 변경 사항이 세 번 나타납니다.

이 예와 동일합니다.

>>> inner = [1,1,1,1]
>>> outer = [inner]*3
>>> outer
[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
>>> inner[0] = 5
>>> outer
[[5, 1, 1, 1], [5, 1, 1, 1], [5, 1, 1, 1]]

아마도 조금 놀랍지 않을 것입니다.

Python-2.x 사용을 사용하는 경우, 목록 이해 내에서 문제를 올바르게 설명하는 수용된 답변과 함께 xrange() 더 효율적인 발전기를 반환합니다 (range() Python 3에서 동일한 작업을 수행합니다) _ Throwaway 변수 대신 n:

[[1]*4 for _ in xrange(3)]      # and in python3 [[1]*4 for _ in range(3)]

또한 훨씬 더 피티닉 사용할 수있는 방법 itertools.repeat() 반복 된 요소의 반복자 객체를 만들려면 :

>>> a=list(repeat(1,4))
[1, 1, 1, 1]
>>> a[0]=5
>>> a
[5, 1, 1, 1]

추신 : Numpy를 사용하면, 당신이 사용할 수있는 것만 만들고 싶다면 사용할 수 있습니다. np.ones 그리고 np.zeros 및/또는 다른 번호 사용 np.repeat():

In [1]: import numpy as np

In [2]: 

In [2]: np.ones(4)
Out[2]: array([ 1.,  1.,  1.,  1.])

In [3]: np.ones((4, 2))
Out[3]: 
array([[ 1.,  1.],
       [ 1.,  1.],
       [ 1.,  1.],
       [ 1.,  1.]])

In [4]: np.zeros((4, 2))
Out[4]: 
array([[ 0.,  0.],
       [ 0.,  0.],
       [ 0.,  0.],
       [ 0.,  0.]])

In [5]: np.repeat([7], 10)
Out[5]: array([7, 7, 7, 7, 7, 7, 7, 7, 7, 7])

간단한 말로 이것은 파이썬에서 모든 것이 작동하기 때문에 일어나고 있습니다. 참조로, 따라서 목록 목록을 이렇게 만들 때 기본적으로 그러한 문제가 발생합니다.

문제를 해결하려면 문제 중 하나를 수행 할 수 있습니다. 1. Numpy Array를 사용하십시오. numpy.empty에 대한 문서2. 목록에 도달하면 목록을 추가하십시오. 3. 원하는 경우 사전을 사용할 수도 있습니다

파이썬 컨테이너에는 다른 물체에 대한 참조가 포함되어 있습니다. 이 예를 참조하십시오 :

>>> a = []
>>> b = [a]
>>> b
[[]]
>>> a.append(1)
>>> b
[[1]]

이것에서 b 목록에 대한 참조 인 하나의 항목을 포함하는 목록입니다. a. 목록 a 변이 가능합니다.

정수에 의한 목록의 곱셈은 목록을 여러 번 추가하는 것과 같습니다 ( 일반적인 시퀀스 작업). 따라서 예를 계속 유지합니다.

>>> c = b + b
>>> c
[[1], [1]]
>>>
>>> a[0] = 2
>>> c
[[2], [2]]

목록을 볼 수 있습니다 c 이제 목록에 대한 두 가지 참조가 포함되어 있습니다 a 이는 동등합니다 c = b * 2.

Python FAQ는 또한이 동작에 대한 설명도 포함합니다. 다차원 목록을 어떻게 만들려면?

myList = [[1]*4] * 3 하나의 목록 개체를 만듭니다 [1,1,1,1] 메모리에서 참조를 3 배 이상 복사합니다. 이것은 동일합니다 obj = [1,1,1,1]; myList = [obj]*3. 모든 수정 obj 어디에서나 세 곳에 반영됩니다 obj 목록에 참조됩니다. 올바른 진술은 다음과 같습니다.

myList = [[1]*4 for _ in range(3)]

또는

myList = [[1 for __ in range(4)] for _ in range(3)]

여기에 주목해야 할 중요한 사항 그게 다 * 운영자입니다 주로 a를 만드는 데 사용됩니다 리터럴 목록. 부터 1 문자 그대로이므로 obj =[1]*4 만들 것입니다 [1,1,1,1] 각각 1 원자체이고 ~ 아니다 의 참조 1 4 번 반복. 이것은 우리가한다면 의미합니다 obj[2]=42, 그 다음에 obj 될 것입니다 [1,1,42,1] ~ 아니다 [42,42,42,42] 일부는 가정 할 수 있습니다.

다음과 같은 방식으로 코드를 다시 작성하겠습니다.

x = 1
y = [x]
z = y * 4

myList = [z] * 3

그런 다음 다음 코드를 실행하여 모든 것을 더 명확하게 만듭니다. 코드가하는 일은 기본적으로 인쇄하는 것입니다 id얻은 물체의 s

객체의“정체성”을 반환하십시오

그리고 우리가 그것들을 식별하고 어떤 일이 일어나는지 분석하는 데 도움이 될 것입니다.

print("myList:")
for i, subList in enumerate(myList):
    print("\t[{}]: {}".format(i, id(subList)))
    for j, elem in enumerate(subList):
        print("\t\t[{}]: {}".format(j, id(elem)))

다음과 같은 출력을 얻을 수 있습니다.

x: 1
y: [1]
z: [1, 1, 1, 1]
myList:
    [0]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528
    [1]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528
    [2]: 4300763792
        [0]: 4298171528
        [1]: 4298171528
        [2]: 4298171528
        [3]: 4298171528

이제 단계별로 가자. 당신은 가지고 있습니다 x 그게 1, 및 단일 요소 목록 y 포함 x. 첫 번째 단계는입니다 y * 4 새로운 목록을 얻을 수 있습니다 z, 기본적으로 [x, x, x, x], 즉, 4 개의 요소가있는 새 목록을 만듭니다. x 물체. 순 단계는 꽤 비슷합니다. 당신은 기본적으로합니다 z * 3, 그것은 [[x, x, x, x]] * 3 그리고 반환 [[x, x, x, x], [x, x, x, x], [x, x, x, x]], 첫 번째 단계와 같은 이유로.

모두가 무슨 일이 일어나고 있는지 설명하는 것 같아요. 나는 그것을 해결하는 한 가지 방법을 제안합니다.

myList = [[1 for i in range(4)] for j in range(3)]

myList[0][0] = 5

print myList

그리고 당신은 다음과 같습니다.

[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]

더 설명 적으로 설명하려고 노력하고

작동 1 : :

x = [[0, 0], [0, 0]]
print(type(x)) # <class 'list'>
print(x) # [[0, 0], [0, 0]]

x[0][0] = 1
print(x) # [[1, 0], [0, 0]]

작동 2 : : : : : : 작동 2 :

y = [[0] * 2] * 2
print(type(y)) # <class 'list'>
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [1, 0]]

첫 번째 목록의 첫 번째 요소를 수정하지 않는 이유가 각 목록의 두 번째 요소를 수정하지 않았습니까? 그것은 ~ 때문에 [0] * 2 실제로 두 숫자 목록이며 0에 대한 참조는 수정할 수 없습니다.

클론 사본을 만들려면 작동 3을 시도해보십시오.

import copy
y = [0] * 2   
print(y)   # [0, 0]

y = [y, copy.deepcopy(y)]  
print(y) # [[0, 0], [0, 0]]

y[0][0] = 1
print(y) # [[1, 0], [0, 0]]

클론 사본을 만드는 또 다른 흥미로운 방법, 작동 4 :

import copy
y = [0] * 2
print(y) # [0, 0]

y = [copy.deepcopy(y) for num in range(1,5)]
print(y) # [[0, 0], [0, 0], [0, 0], [0, 0]]

y[0][0] = 5
print(y) # [[5, 0], [0, 0], [0, 0], [0, 0]]

내장 목록 기능을 사용하면 다음과 같이 할 수 있습니다.

a
out:[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#Displaying the list

a.remove(a[0])
out:[[1, 1, 1, 1], [1, 1, 1, 1]]
# Removed the first element of the list in which you want altered number

a.append([5,1,1,1])
out:[[1, 1, 1, 1], [1, 1, 1, 1], [5, 1, 1, 1]]
# append the element in the list but the appended element as you can see is appended in last but you want that in starting

a.reverse()
out:[[5, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
#So at last reverse the whole list to get the desired list
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top