파이썬은 여러 변수를 같은 값으로 할당합니까? 행동 목록


132

변수를 초기화하기 위해 아래에 표시된 것처럼 여러 대입을 사용하려고했지만 동작에 혼란스러워서 값 목록을 별도로 다시 할당 할 것으로 예상합니다. 전과 같이 b [0]과 c [0]이 0임을 의미합니다.

a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)

결과 : [1, 3, 5] [1, 3, 5] [1, 3, 5]

그 맞습니까? 여러 과제에 무엇을 사용해야합니까? 이것과 다른 점은 무엇입니까?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

결과 : ( 'f :', 3) ( 'e :', 4)


2
당신이 원하는 수행 a, b그리고 c,(이 경우 목록) 같은 값에 대한 모든 지점, 또는 당신이 원하는 할 a=0, b=3하고 c=5. 이 경우 원하는 a,b,c = [0,3,5]또는 a,b,c = 0,3,5.
chepner

답변:


271

C / Java / etc의 언어에서 Python으로오고 있다면 a"가변"이라고 생각하지 않고 "이름"으로 생각하기 시작하는 것이 도움이 될 수 있습니다 .

a, bc값이 같은 변수가 아닙니다. 그들은 동일한 동일한 값을 위해 다른 이름입니다. 변수에는 유형, ID, 주소 및 모든 종류의 것들이 있습니다.

이름은 그 중 하나도 없습니다. 값은 물론, 할, 당신은 같은 값의 이름을 많이 할 수 있습니다.

Notorious B.I.G.핫도그 를주고 * 핫도그 Biggie SmallsChris Wallace가지고 있다면. 첫 번째 요소 a를 1로 변경하면 b및 의 첫 번째 요소 c는 1입니다.

두 개의 이름이 같은 객체를 명명하는지 알고 싶다면 is연산자를 사용하십시오 .

>>> a=b=c=[0,3,5]
>>> a is b
True

그런 다음 묻습니다.

이것과 다른 점은 무엇입니까?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

여기에서 이름 e을 값으로 리 바인딩합니다 4. 즉, 이름에 영향을주지 않습니다 df어떤 식 으로든한다.

이전 버전에서는에 할당 a[0]하지 않고에 할당 했습니다 a. 따라서의 관점에서 a[0]리 바인딩하는 것입니다 a[0]. 그러나의 관점에서는 a그 위치를 변경하고 있습니다.

id객체의 아이덴티티를 나타내는 고유 번호를 제공 하는 함수를 사용하면 어떤 객체가 is도움이 될 수 없는지 정확하게 알 수 있습니다.

>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120

>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216

공지 사항 a[0]4297261120로 변경되었습니다 4297261216는 - 지금 다른 값의 이름입니다. 그리고 b[0]이제 같은 새로운 가치의 이름이기도합니다. 그 때문에 a그리고 b여전히 같은 개체의 이름을 지정합니다.


커버 아래에서 a[0]=1실제로 목록 객체에서 메소드를 호출합니다. (이것은에 해당합니다 a.__setitem__(0, 1).) 따라서 실제로는 아무 것도 리 바인드 하지 않습니다 . 전화하는 것과 같습니다 my_object.set_something(1). 물론, 객체가이 메소드를 구현하기 위해 인스턴스 속성을 리 바인드하고있을 수도 있지만, 중요하지는 않습니다. 중요한 것은 아무것도 할당하지 않고 객체를 변경하는 것입니다. 와 동일합니다 a[0]=1.


사용자 요청 :

우리가 가지고 있다면 a = b = c = 10

그것은 정확히 같은 상황 a = b = c = [1, 2, 3]입니다. 같은 값을 가진 세 개의 이름이 있습니다.

그러나이 경우 값은 int이며 ints는 변경할 수 없습니다. 각각의 경우에, 당신은 바인딩 할 수 a다른 값 (예를 들어,에 a = "Now I'm a string!")하지만, 원래 값에 영향을 미치지 않습니다 bc아직의 이름이 될 것이다. 차이는 목록, 값을 변경 할 수 있다는 것입니다 [1, 2, 3]으로 [1, 2, 3, 4]수행하여, 예를 들면 a.append(4); 즉 실제로하는 가치 변화하고 있기 때문에 bc에 대한 이름은을, b지금 ㄱ 것이다 [1, 2, 3, 4]. 값 10을 다른 것으로 바꿀 방법이 없습니다. 10뱀파이어가 영원히 5 일 때와 마찬가지로 (최소한 그녀는 Kirsten Dunst로 교체 될 때까지)


* 경고 : 악명 높은 BIG에게 핫도그를주지 마십시오. 자정 이후에는 갱스터 랩 좀비를 먹여서는 안됩니다.


우리 have, a = b = c = 10;와 b의 값을 업데이트하려고 할 때 다른 효과가 있습니까? 비록 그들의 ID가 같은지 확인했지만.?
AJ

@ user570826 : 10변경할 수 없습니다. 즉, 값을 업데이트 할 방법이 없으므로 질문이 이해가되지 않습니다. b다른 값을 가리킬 수 있지만 그렇게 해도 원래 값을 가리키는 a및에 영향을 미치지 않습니다 c. 목록의 차이점은 목록을 변경할 수 있다는 것입니다. 예를 들어 append목록 lst[0] = 3으로 또는를 통해 값을 업데이트하면 해당 값의 모든 이름을 통해 볼 수 있습니다.
abarnert

72

기침

>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>> 

10
IMHO, 이것은 실제로 여러 과제에 무엇을 사용 해야하는지에 대한 OP 첫 번째 주요 질문에 대답하지만 위의 더 높은 등급과 더 많은 대뇌 대답은 그렇지 않습니다.
윌 Croxford

2
또는 a,b,c = 1,2,3대괄호가 없으면 파이썬 2 또는 3에서 작동합니다.
Will Croxford

14

예, 이것이 예상되는 동작입니다. a, b 및 c는 모두 동일한 목록에 대한 레이블로 설정됩니다. 세 개의 다른 목록을 원하면 개별적으로 할당해야합니다. 명시 적 목록을 반복하거나 다양한 방법 중 하나를 사용하여 목록을 복사 할 수 있습니다.

b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects

파이썬에서 대 입문은 객체를 복사하지 않습니다. 그것들은 이름을 객체에 바인딩하며, 객체는 설정 한만큼 많은 레이블을 가질 수 있습니다. 첫 번째 편집에서 a [0]을 변경하면 a, b 및 c가 모두 참조하는 단일 목록의 한 요소가 업데이트됩니다. 두 번째로 e를 변경하면 e를 다른 객체의 레이블 (3 대신 4)로 전환합니다.


13

파이썬에서는 모든 것이 객체이며 "단순한"변수 유형 (int, float 등)도 있습니다.

변수 값을 변경하면 실제로는 포인터 가 바뀌고 두 변수를 비교하면 포인터 가 비교 됩니다. (포인터는 변수가 저장된 실제 컴퓨터 메모리의 주소입니다).

결과적으로 내부 변수 값을 변경하면 메모리의 값이 변경되고이 주소를 가리키는 모든 변수에 영향을줍니다.

예를 들어, 다음과 같은 경우 :

a = b =  5 

이것은 a와 b가 메모리에 값 5를 포함하는 동일한 주소를 가리 키지 만 다음과 같은 경우를 의미합니다.

a = 6

a가 6을 포함하는 다른 메모리 위치를 가리키고 b가 여전히 5를 포함하는 메모리 주소를 가리 키기 때문에 b에 영향을 미치지 않습니다.

그러나 할 때 :

a = b = [1,2,3]

a와 b는 다시 같은 위치를 가리 키지 만 차이점은 목록 값 중 하나를 변경하면 다음과 같습니다.

a[0] = 2

a가 가리키는 메모리 값을 변경하지만 a는 여전히 b와 동일한 주소를 가리 키므로 b도 변경됩니다.


6
이것은 매우 잘못된 것입니다. 포인터는 확실히 파이썬 수준에서는 보이지 않으며, 4 가지 주요 구현 중 2 개 (PyPy 및 Jython) 중 적어도 2 개는 구현 내부에서도 사용하지 않습니다.
abarnert

1
파이썬 내부를 읽고 탐구하는 것을 환영하며 파이썬의 모든 변수가 실제로 포인터라는 것을 알게 될 것입니다.
오리 세리

4
아니요. Python (CPython)의 한 구현 에서 모든 변수는에 대한 포인터 PyObject입니다. PyPy 또는 Jython과 같은 다른 구현에서는 그렇지 않습니다. (실제로 구현이 작성된 언어에는 포인터가 없기 때문에 그것이 어떻게 실현 될 있는지는 확실 하지 않습니다.)
abarnert

나는 개념적 의미에서 "포인터"를 사용하는 것이 좋다고 생각합니다 (아마도 구현이 다를 수있는 고지 사항이있을 수 있음).
Levon

@abarnert 사람들이 파이썬이라고 말할 때 다른 거의 사용되지 않는 구현은 CPython을 의미합니다. 사람들이 Kleenex를 말할 때와 마찬가지로 얼굴 조직을 의미합니다. 이 의견에서 의미 게임을하는 것은 실제로 필요하지 않습니다. 그가 쓴 것에 관해서는, 그가 묘사 한 행동이 잘못 되었습니까?
18:44에

10

id(name)두 개의 이름이 동일한 객체를 나타내는 지 확인할 수 있습니다 .

>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488

리스트는 변경 가능합니다. 즉, 새 객체를 만들지 않고도 값을 제자리에서 변경할 수 있습니다. 그러나 값을 변경하는 방법에 따라 다릅니다.

>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]

에 새 목록을 할당하면 a해당 ID가 변경되므로 bc의 값에 영향을 미치지 않습니다 .

>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]

정수는 변경할 수 없으므로 새 객체를 만들지 않고 값을 변경할 수 없습니다.

>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1

1
id반드시 메모리 위치는 아닙니다. 문서에서 알 수 있듯이 , 이것은 "정체성 ... 정수… 이것은 평생 동안이 개체에 대해 독특하고 일정하게 보장됩니다."를 반환합니다. CPython은 메모리 주소를로 사용 id하지만 다른 파이썬 구현에서는 그렇지 않을 수 있습니다. 예를 들어 PyPy는 그렇지 않습니다. 그리고 "두 가지 변수가 동일한 메모리 위치를 가리킨다"고 말하는 것은 C 스타일을 이해하는 사람에게는 오해의 소지가 있습니다. "같은 객체에 대한 두 개의 이름"은 더 정확하고 오해의 소지가 없습니다.
abarnert

@abarnert는 설명을 해 주셔서 감사합니다. 대답을 업데이트했습니다.
jurgenreza

7

첫 번째 예 a = b = c = [1, 2, 3]에서는 실제로 다음과 같이 말합니다.

 'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]

'a'를 1, 'b'를 '2', 'c'를 3으로 설정하려면 다음을 시도하십시오.

a, b, c = [1, 2, 3]

print(a)
--> 1
print(b)
--> 2
print(c)
--> 3

도움이 되었기를 바랍니다!


4

간단히 말해서 첫 번째 경우에는 여러 이름을에 할당하는 것 list입니다. 하나의 목록 사본 만 메모리에 작성되며 모든 이름은 해당 위치를 참조합니다. 따라서 이름을 사용하여 목록을 변경하면 실제로 메모리의 목록이 수정됩니다.

두 번째 경우, 동일한 값의 여러 사본이 메모리에 작성됩니다. 따라서 각 사본은 서로 독립적입니다.


3

필요한 것은 이것입니다.

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1             # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)

3

내가 필요한 것을 수행하는 코드는 다음과 같습니다.

# test

aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)

# initialization

a,b,c,d=[[0 for n in range(3)] for i in range(4)]

# changing values

a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)

결과:

('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.