복붙노트

[PYTHON] 무한 중첩 목록에서 정확히 무슨 일이 일어나고 있습니까?

PYTHON

무한 중첩 목록에서 정확히 무슨 일이 일어나고 있습니까?

파이썬에서 무한 중첩리스트를 만드는 것이 가능합니다. 그것은 분명하고 대중적이지는 않지만 명확하지는 않지만 알려진 사실입니다.

>>> a = [0]
>>> a[0] = a
>>> a
[[...]]
>>> a[0] == a
True

제 질문은, 여기서 일어나는 일입니다.

>>> a = [0]
>>> b = [0]
>>> a[0], b[0] = b, a
>>> a
[[[...]]]
>>> b
[[[...]]]
>>> a == b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: maximum recursion depth exceeded in cmp
>>> a[0] == b
True
>>> a[0][0] == b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: maximum recursion depth exceeded in cmp
>>> a[0][0][0] == b
True
>>> 

더 깊은 곳에서, 내가 그것을 이해하려고 할 때, 나는 나의 뇌가 폭발 할 것 같은 느낌을 더줍니다. 나는 a가 a를 포함하고 b를 포함하는 것을 본다.

이제이 질문에 대한 나의 질문. 우리는 정말로 여기에 두 가지 목록을 가지고 있습니까? 어떻게 이런 일이 메모리에 저장 되나요? 프로그래머가 이렇게 이상한 것을 구현할 수있게하는 목적은 무엇일까요?

제발,이 질문을 매우 심각하게 생각하지 마십시오. 잊지 말라. 프로그래밍은 때때로 재미있을 수있다.

해결법

  1. ==============================

    1.면책 조항 : 저는 파이썬을 사용하지 않습니다, 그래서 제가 말하는 것은 틀릴 수도 있습니다. 파이썬 전문가는 저를 시정 해 줄 것입니다.

    면책 조항 : 저는 파이썬을 사용하지 않습니다, 그래서 제가 말하는 것은 틀릴 수도 있습니다. 파이썬 전문가는 저를 시정 해 줄 것입니다.

    좋은 질문입니다. 나는 중앙 오개념 (만약 내가 그것을 심지어 호출 할 수 없다면, 당신이 사용한 사고 과정에 어떻게 도달했는지 완벽하게 합리적이라고 생각한다)을 묻는 질문을하는 것이 이것이다.

    b [0] = a라고 쓸 때, a가 b에 있음을 의미하지는 않습니다. 그것은 b가 가리키는 것을 가리키는 참조를 포함한다는 것을 의미합니다.

    변수 a와 b 자체는 "사물"자체조차도 아니며, 메모리 자체의 익명의 "사물"에 대한 포인터이기도합니다.

    참조 개념은 비 프로그래밍 세계에서 큰 도약이므로이 점을 염두에두고 프로그램을 단계별로 살펴 보겠습니다.

    >>> a = [0]
    

    당신은 무언가를 가지고있는 목록을 생성합니다 (지금은 무시하십시오). 중요한 것은 목록입니다. 그 목록은 메모리에 저장됩니다. 메모리 위치 1001에 저장되어 있다고 가정 해 봅니다. 그런 다음 할당 =은 프로그래밍 언어에서 나중에 사용할 수있는 변수 a를 만듭니다. 이 시점에서 메모리에 몇 가지 목록 객체가 있으며 그 객체에 대한 참조는 이름으로 액세스 할 수 있습니다.

    >>> b = [0]
    

    이것은 b와 같은 일을합니다. 메모리 위치 (1002)에 저장되는 새로운리스트가있다. 프로그래밍 언어는 메모리 위치 및 차례로리스트 객체를 참조하는데 사용할 수있는 참조 b를 생성한다.

    >>> a[0], b[0] = b, a
    

    이것은 두 가지가 동일하므로 하나에 초점을 맞추어 보겠습니다. a [0] = b. 이것이하는 일은 꽤 환상적입니다. 그것은 먼저 평등의 오른쪽을 평가하고 변수 b를보고 b가 메모리에 대한 참조이므로 메모리 (메모리 객체 # 1002)에서 해당 객체를 가져옵니다. 왼쪽에서 일어나는 일은 똑같이 환상적입니다. a는리스트 (메모리 오브젝트 # 1001)를 가리키는 변수이지만, 메모리 오브젝트 # 1001 그 자체는 다수의 자체 참조를가집니다. 여러분이 사용하는 a와 b와 같은 이름을 가진 레퍼런스 대신 0과 같은 숫자 인덱스를 사용합니다. 따라서 지금은 인덱스 된 레퍼런스 더미 인 메모리 오브젝트 # 1001을 가져옵니다. 인덱스 0 (이전에는이 ​​참조가 실제 숫자 0을 가리켰습니다.이 값은 1 행에서 수행 한 것입니다). 그런 다음 해당 참조 (즉, 메모리 오브젝트 # 1001의 첫 번째 및 유일한 참조)를 방정식의 오른쪽에있는 값은로 평가됩니다. 이제 개체 # 1001의 0 번째 참조가 개체 # 1002를 가리 킵니다.

    >>> a
    [[[...]]]
    >>> b
    [[[...]]]
    

    이것은 프로그래밍 언어에 의해 완성 된 단지 환상입니다. a를 평가하도록 요청하면 메모리 오브젝트 (위치 # 1001의 목록)를 위로 당기고, 자신의 마법을 사용하여 무한하다는 것을 감지하고 그 자체로 렌더링합니다.

    >>> a == b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    RuntimeError: maximum recursion depth exceeded in cmp
    

    이 문장의 실패는 파이썬이 어떻게 비교하는지와 관련이있다. 객체를 자체 객체와 비교하면 즉시 true로 평가됩니다. 다른 개체와 비교하고 반대 할 때 "마법"을 사용하여 등호가 참인지 거짓인지를 결정합니다. 파이썬의 목록의 경우, 각 목록의 모든 항목을 살펴본 후 항목의 등호 검사 방법을 사용하여 항목이 같은지 확인합니다. 그래서, 시도 할 때 == b. 그것이하는 일은 먼저 b (객체 # 1002)와 (객체 # 1001)을 파고 메모리에서 다른 것들이 있다는 것을 깨닫고 재귀 목록 검사기로 간다. 이 작업은 두 목록을 반복하여 수행합니다. 오브젝트 # 1001에는 오브젝트 # 1002를 가리키는 인덱스 0의 요소가 하나 있습니다. 오브젝트 # 1002에는 오브젝트 # 1001을 가리키는 인덱스 0의 요소가 하나 있습니다. 따라서 프로그램은 # 1001과 # 1002가 모두 같은 점을 가리킨다면 # 1002 (# 1001의 유일한 참조 점)와 # 1001 (# 1002의 유일한 참조 점)은 같다고 결론 짓는다. 똑같은 것. 이러한 동등성 검사는 결코 멈출 수 없습니다. 멈추지 않는 목록에서도 똑같은 일이 일어날 것입니다. 당신은 할 수있는 c = [0]; d = [0]; c [0] = d; d [0] = c 및 a == c는 동일한 오류를 발생시킵니다.

    >>> a[0] == b
    True
    

    앞 단락에서 암시 한 바와 같이, 파이썬이 바로 가기를 취하기 때문에이 사실은 즉시 해결됩니다. [0]은 객체 # 1002를 가리키고 b는 객체 # 1002를 가리키기 때문에리스트 내용을 비교할 필요가 없습니다. 파이썬은 문자 적 ​​의미에서 동일하다는 것을 감지하고 (동일한 "것") 내용을 확인하는 것을 방해하지 않습니다.

    >>> a[0][0] == b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    RuntimeError: maximum recursion depth exceeded in cmp
    

    [0] [0]이 오브젝트 # 1001을 가리 키기 때문에 이것은 오류가됩니다. 신원 확인이 실패하고 다시 끝나는 절대적 컨텐트 검사로 되돌아갑니다.

    >>> a[0][0][0] == b
    True
    

    다시 한번, [0] [0] [0]은 b와 마찬가지로 객체 # 1002를 가리 킵니다. 재귀 확인은 건너 뛰고 비교는 즉시 true를 반환합니다.

    특정 코드 스 니펫과 직접적으로 관련이없는 높은 수준의 jibber jabber :

  2. ==============================

    2.나는 다음과 같은 일이 일어날 것으로 생각한다.

    나는 다음과 같은 일이 일어날 것으로 생각한다.

    a [0] == b : 파이썬은 값 a [0]을 찾아 b에 대한 일종의 참조를 찾습니다. 그래서 True를 말합니다.

    a [0] [0] == b : 파이썬은 a [0]을 찾아 b를 찾고 a [0] [b] b [0]이므로 a [0] [0]을 찾습니다. 이제는 b [0]이 a와 어떤 종류의 참조를 가지고 있다는 것을 보았습니다. 이것은 b와 정확히 같지 않습니다. 따라서 python은 요소를 비교해야합니다. 즉 a [0]과 b [0]을 비교해야합니다. 자, 무한 재귀가 시작됩니다 ...

    이것은 [0] = b를 할당 할 때 실제로 파이썬이리스트를 복사하지 않기 때문에 작동합니다. 파이썬은 오히려 [0]에 저장된 b에 대한 참조를 만듭니다.

  3. ==============================

    3.a [0]은 b를 나타내고 b [0]은 a를 나타냅니다. 이것은 순환 참조입니다. glglgl에서 언급했듯이 == 연산자를 사용하면 값의 비교를 수행합니다.

    a [0]은 b를 나타내고 b [0]은 a를 나타냅니다. 이것은 순환 참조입니다. glglgl에서 언급했듯이 == 연산자를 사용하면 값의 비교를 수행합니다.

    이것을 시도하면 더 명확하게 알 수 있습니다.

    >>> id(a)
    4299818696
    >>> id(b)
    4299818768
    >>> id(a[0])
    4299818768
    >>> 
    >>> id(b[0])
    4299818696
    
  4. ==============================

    4.그들은 서로를 포함하지 않습니다. A는 목록에 대한 참조이고,이 목록의 첫 번째 것은 B에 대한 참조이고, 그 반대의 경우도 마찬가지입니다.

    그들은 서로를 포함하지 않습니다. A는 목록에 대한 참조이고,이 목록의 첫 번째 것은 B에 대한 참조이고, 그 반대의 경우도 마찬가지입니다.

    >>> a[0] == b
    True
    >>> a[0][0] == b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    RuntimeError: maximum recursion depth exceeded in cmp
    >>> a[0][0][0] == b
    True
    

    원하는만큼 많은 목록 조회를 할 수 있기 때문에 [0]의 개수는 중요하지 않습니다. 중요한 것은 예제 # 1 및 # 3 (그리고 모든 홀수의 조회수)에서 " 파이썬은 메모리 주소를 비교하여 똑같은지 확인합니다. 그렇습니다. 그렇습니다. 예제 # 2 (그리고 모든 짝수 조회)에서 "A가 B와 같습니다"라고 말하면 파이썬은 서로 다른 메모리 주소임을 확인한 다음 전체 (무한) 데이터 구조를 메모리에로드하여보다 많은 인 - 깊이 비교.

  5. ==============================

    5.이들은 두 가지 목록입니다. 먼저, 다음과 같이 만듭니다.

    이들은 두 가지 목록입니다. 먼저, 다음과 같이 만듭니다.

    a = [0]
    b = [0]
    

    그런 다음 각 요소를 다른 요소의 첫 번째 요소에 할당합니다.

    a[0], b[0] = b, a
    

    그래서 당신은 말할 수 있습니다.

    a[0] is b
    

    b[0] is a
    

    이것은 첫 번째 예와 동일한 상황이지만 깊이가 더 깊다.

    또한 신원 (is)은 같지 않지만 평등 (==)은 비교합니다. 이것은 그들을 비교하려고 시도합니다. 내부 깊숙한 곳, 재귀가되는 곳.

  6. from https://stackoverflow.com/questions/7674685/whats-exactly-happening-in-infinite-nested-lists by cc-by-sa and MIT license