파이썬의 변수는 내가 아는 한 포인터 일뿐입니다.
이 규칙에 따라이 코드 조각의 결과를 가정 할 수 있습니다.
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
받는 동일한 목록 객체입니다. 목록의 내용을 수정하면 목록을 참조하는 데 사용하는 이름에 관계없이 변경 사항을 볼 수 있습니다.
“두 목록이 모두 변경되었습니다”라고 말하면 올바르지 않습니다. 목록은 하나 뿐이지 만이 를 참조하는 두 개의 이름 ( i
및 j
)이 있습니다.
관련 문서
답변
파이썬 변수는 객체에 묶인 이름입니다
로부터 문서 :
이름은 개체를 나타냅니다. 이름은 이름 바인딩 작업에 의해 도입됩니다. 프로그램 텍스트 에서 이름 이 나타날 때마다 사용을 포함하는 가장 안쪽의 기능 블록에 설정된 이름의 바인딩을 나타냅니다 .
당신이 할 때
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]
지금 i
과 j
같은 목록을 모두 가리 킵니다. 그런 다음 귀하의 예제는 목록을 변경합니다.
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.j
i[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 list
은 PyObject*
내부적 으로 포인터 의 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]
두 이름이 가리키는 객체의 요소를 변경 했습니다.
기존 복합 객체의 값이 변경 될 수 있습니다.
이름을 통해 개체의 값을 변경할 때 이름은 변경되지 않습니다. 모두 i
와 j
여전히 값이 우리가 변경할 수있는 동일한 객체를 참조하십시오.
+- 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를 인쇄합니다