[python] 파이썬 변수 포인터입니까? 아니면 그들은 무엇입니까?

파이썬의 변수는 내가 아는 한 포인터 일뿐입니다.

이 규칙에 따라이 코드 조각의 결과를 가정 할 수 있습니다.

i = 5
j = i
j = 3
print(i)

될 것 3입니다. 하지만 예상치 못한 결과를 얻었습니다 5.

또한 내 Python 책은이 예제를 다루고 있습니다.

i = [1,2,3]
j = i
i[0] = 5
print(j)

결과는입니다 [5,2,3].

내가 무엇을 잘못 이해하고 있습니까?



답변

우리는 그것들을 참조라고 부릅니다. 그들은 이렇게 작동합니다

i = 5     # create int(5) instance, bind it to i
j = i     # bind j to the same int as i
j = 3     # create int(3) instance, bind it to j
print i   # i still bound to the int(5), j bound to the int(3)

작은 정수는 인턴이지만이 설명에서는 중요하지 않습니다.

i = [1,2,3]   # create the list instance, and bind it to i
j = i         # bind j to the same list as i
i[0] = 5      # change the first item of i
print j       # j is still bound to the same list as i


답변

변수는 포인터가 아닙니다. 변수에 할당 하면 이름을 개체에 바인딩 하는 것입니다. 그 이후부터는 이름이 리 바인드 될 때까지 이름을 사용하여 객체를 참조 할 수 있습니다.

첫 번째 예에서 이름 i은 값에 바인딩됩니다 5. 이름에 다른 값을 바인딩 j해도 영향을주지 않으므로 i나중에 인쇄 할 때 값의 i값은 그대로 유지 5됩니다.

두 번째 예에서는 모두 결합 i하고 j받는 동일한 목록 객체입니다. 목록의 내용을 수정하면 목록을 참조하는 데 사용하는 이름에 관계없이 변경 사항을 볼 수 있습니다.

“두 목록이 모두 변경되었습니다”라고 말하면 올바르지 않습니다. 목록은 하나 뿐이지 만이 를 참조하는 두 개의 이름 ( ij)이 있습니다.

관련 문서


답변

파이썬 변수는 객체에 묶인 이름입니다

로부터 문서 :

이름은 개체를 나타냅니다. 이름은 이름 바인딩 작업에 의해 도입됩니다. 프로그램 텍스트 에서 이름 이 나타날 때마다 사용을 포함하는 가장 안쪽의 기능 블록에 설정된 이름의 바인딩을 나타냅니다 .

당신이 할 때

i = 5
j = i

다음과 같이하는 것과 같습니다.

i = 5
j = 5

j을 가리 키지 않고 i할당 후에 j그것이 i존재 하는지 모릅니다 . 할당 당시에 가리키는 j모든 i것에 묶여 있습니다.

같은 줄에 할당을했다면 다음과 같습니다.

i = j = 5

그리고 결과는 똑같을 것입니다.

따라서 나중에

i = 3

j가리키는 내용을 변경하지 않고 바꿀 수 있습니다 . 가리키는 내용을 j = 3변경하지 않습니다 i.

귀하의 예제는 목록에 대한 참조를 제거하지 않습니다.

따라서 이렇게하면 :

i = [1,2,3]
j = i

이 작업을 수행하는 것과 동일합니다.

i = j = [1,2,3]

지금 ij같은 목록을 모두 가리 킵니다. 그런 다음 귀하의 예제는 목록을 변경합니다.

i[0] = 5

파이썬 목록은 변경 가능한 객체이므로 한 참조에서 목록을 변경하고 다른 참조에서 볼 때 동일한 목록이므로 동일한 결과를 볼 수 있습니다.


답변

TLDR : Python 이름 은 자동 역 / 참조가있는 포인터처럼 작동하지만 명시 적 포인터 작업을 허용하지 않습니다. 다른 대상은 포인터와 유사하게 작동하는 간접적을 나타냅니다.


CPython 구현은 내부적 으로 유형의 포인터를PyObject* 사용합니다 . 따라서 이름 의미를 포인터 작업으로 변환 할 수 있습니다. 핵심은 실제 개체이름 을 구분하는 것 입니다.

예제 Python 코드에는 이름 ( i)과 객체 ( 5)가 모두 포함됩니다 .

i = 5  # name `i` refers to object `5`
j = i  # ???
j = 3  # name `j` refers to object `3`

이것은 대략 별도의 이름과 객체를 가진 C 코드로 변환 될 수 있습니다 .

int three=3, five=5;  // objects
int *i, *j;           // names
i = &five;   // name `i` refers to position of object `5`
j = i;       // name `j` refers to referent of `i`
j = &three;  // name `j` refers to position of object `3`

중요한 부분은 “포인터로서의 이름”은 객체를 저장하지 않는다는 것입니다! 우리는 정의하지 *i = five않았지만 i = &five. 이름과 개체는 서로 독립적으로 존재합니다.

이름 은 메모리의 기존 개체 만 가리 킵니다 .

이름에서 이름으로 할당 할 때 개체가 교환되지 않습니다! 우리가 정의 할 때 j = i이것은 j = &five. 둘 다 다른 것과 연결되어 있지 i않습니다 j.

+- name i -+ -\
               \
                --> + <five> -+
               /    |        5 |
+- name j -+ -/     +----------+

따라서 한 이름의 대상을 변경해도 다른 이름에는 영향을주지 않습니다 . 특정 이름이 가리키는 것만 업데이트합니다.


파이썬에는 또한 속성 참조 ( ), 구독 ( ) 및 슬라이싱 ( ) 과 같은 다른 종류의 이름과 유사한 요소가 있습니다. 개체를 직접 참조하는 이름과 달리 세 가지 모두 개체의 요소를 간접적으로 참조 합니다.i.ji[j]i[:j]

예제 코드에는 이름 ( i)과 구독 ( i[0])이 모두 포함됩니다 .

i = [1,2,3]  # name `i` refers to object `[1, 2, 3]`
j = i        # name `j` refers to referent of `i`
i[0] = 5     # ???

CPython listPyObject*내부적 으로 포인터 의 C 배열을 사용합니다 . 이것은 다시 대략적인 이름과 객체를 가진 C 코드로 변환 될 수 있습니다.

typedef struct{
    int *elements[3];
} list;  // length 3 `list` type

int one = 1, two = 2, three = 3, five = 5;
list values = {&one, &two, &three};  // objects
list *i, *j;                         // names
i = &values;             // name `i` refers to object `[1, 2, 3]`
j = i;                   // name `j` refers to referent of `i`
i->elements[0] = &five;  // leading element of `i` refers to object `5`

중요한 부분은 우리가 이름을 변경하지 않았다는 것입니다! 우리는 i->elements[0]두 이름이 가리키는 객체의 요소를 변경 했습니다.

기존 복합 객체의 값이 변경 될 수 있습니다.

이름을 통해 개체의 값을 변경할 때 이름은 변경되지 않습니다. 모두 ij여전히 값이 우리가 변경할 수있는 동일한 객체를 참조하십시오.

+- name i -+ -\
               \
                --> + <values> -+
               /    |  elements | --> [1, 2, 3]
+- name j -+ -/     +-----------+

중간 객체 는 가리키는 것을 직접 변경하고 여러 이름에서 참조 할 수 있다는 점에서 포인터와 유사하게 작동 합니다.


답변

그것들은 포인터가 아니라 객체에 대한 참조입니다. 객체는 변경 가능하거나 변경 불가능할 수 있습니다. 변경 불가능한 객체는 수정 될 때 복사됩니다. 변경 가능한 객체는 제자리에서 변경됩니다. 정수는 i 및 j 변수로 참조하는 변경 불가능한 객체입니다. 목록은 변경 가능한 객체입니다.

첫 번째 예에서

i=5
# The label i now references 5
j=i
# The label j now references what i references
j=3
# The label j now references 3
print i
# i still references 5

두 번째 예에서 :

i=[1,2,3]
# i references a list object (a mutable object)
j=i
# j now references the same object as i (they reference the same mutable object)
i[0]=5
# sets first element of references object to 5
print j
# prints the list object that j references. It's the same one as i.


답변

j=3레이블이 j더 이상 적용 (점)되지 않도록 설정 i하면 정수를 가리 키기 시작합니다 3. 이름 i은 여전히 ​​원래 설정 한 값인을 참조합니다 5.


답변

‘=’기호의 왼쪽에있는 변수는 ‘=’의 오른쪽에있는 값으로 할당됩니다.

i = 5

j = i — j는 5

j = 3 — j는 3 (값 5 덮어 쓰기)이지만 i와 관련하여 변경된 사항이 없습니다.

print(i)-그래서 이것은 5를 인쇄합니다