튜플에 가변 항목이 포함될 수있는 이유는 무엇입니까?


178

튜플을 변경할 수없는 경우 왜 변경 가능한 항목을 포함 할 수 있습니까?

목록과 같은 변경 가능한 항목이 수정 될 때 그 목록에 속하는 튜플은 변경 불가능하다는 것이 모순되는 것처럼 보입니다.

답변:


205

훌륭한 질문입니다.

핵심 통찰력은 튜플이 그 내부의 객체가 변경 가능한지 알 수 없다는 것입니다. 객체를 변경 가능하게 만드는 유일한 것은 데이터를 변경하는 메소드를 갖는 것입니다. 일반적으로이를 감지 할 방법이 없습니다.

또 다른 통찰력은 파이썬 컨테이너에 실제로 아무것도 포함되어 있지 않다는 것입니다. 대신 다른 개체에 대한 참조를 유지합니다. 마찬가지로 파이썬의 변수는 컴파일 된 언어의 변수와 다릅니다. 대신 변수 이름은 네임 스페이스 사전에서 해당 객체와 연관된 키일뿐입니다. 네드 배치 헬더 (Ned Batchhelder)는 그의 블로그 포스트 에서 이것을 잘 설명했다 . 어느 쪽이든 객체는 참조 횟수 만 알고 있습니다. 그들은 그 참조가 무엇인지 모릅니다 (변수, 컨테이너 또는 파이썬 내부).

이 두 가지 통찰력을 통해 수수께끼를 설명 할 수 있습니다 (기본 목록이 변경 될 때 목록을 포함하는 불변의 튜플이 변경되는 이유). 실제로 튜플은 변경되지 않았습니다 (이전에는 이전에 수행했던 다른 객체에 대한 동일한 참조가 있음). 튜플은 변경 방법이 없기 때문에 변경할 수 없습니다. 리스트가 변경되었을 때, 튜플은 그 변경을 통지받지 못했습니다 (리스트는 변수, 튜플 또는 다른리스트에 의해 참조되는지 알 수 없습니다).

우리가 주제를 다루는 동안 튜플의 개념, 작동 방식 및 용도에 대한 정신 모델을 완성하는 데 도움이되는 몇 가지 다른 생각이 있습니다.

  1. 튜플은 불변성이 적고 의도 된 목적으로 더 많이 특징 화됩니다.
    튜플은 한 지붕 아래에서 이기종 정보를 수집하는 Python의 방법입니다. 예를 들어, s = ('www.python.org', 80) 호스트 / 포트 쌍을 복합 객체 소켓으로 전달할 수 있도록 문자열과 숫자를 결합합니다. 그러한 관점에서 볼 때 가변 구성 요소를 갖는 것이 완벽합니다.

  2. 불변성은 다른 속성 인 hashability밀접한 관련이 있습니다. 그러나 해시 가능성은 절대적인 속성이 아닙니다. 튜플의 구성 요소 중 하나가 해시 가능하지 않은 경우 전체 튜플도 해시 가능하지 않습니다. 예를 들어, t = ('red', [10, 20, 30])해시 가능하지 않습니다.

마지막 예는 문자열과 목록을 포함하는 2 개의 튜플을 보여줍니다. 튜플 자체는 변경할 수 없습니다 (즉, 내용을 변경하는 메소드가 없습니다). 마찬가지로 문자열에는 변경 방법이 없으므로 문자열을 변경할 수 없습니다. 리스트 오브젝트에는 변경 메소드가 있으므로 변경할 수 있습니다. 이는 가변성이 객체 유형의 속성임을 나타냅니다. 일부 객체에는 변경 방법이 있고 일부는 그렇지 않습니다. 개체가 중첩되어 있어도 변경되지 않습니다.

두 가지를 기억하십시오. 첫째, 불변성은 마술이 아니라 돌연변이 방법이 없다는 것입니다. 둘째, 객체는 변수 또는 컨테이너가 무엇을 참조하는지 알지 못합니다. 참조 횟수 만 알고 있습니다.

희망, 이것은 당신에게 유용했습니다 :-)


"튜플은 그 안에있는 객체가 변경 가능한지 알 수있는 방법이 없습니다." 참조가 해시 메소드를 구현하는지 감지하면 불변입니다. dic이나 세트처럼. 이것은 어떤 튜플이 의도되었는지에 대한 디자인 결정이 아닌가?
garg10may

@ garg10may 1) object ()hash() 에서 상속되는 모든 것이 해시 가능하므로 하위 클래스가 해시를 명시 적으로 해제해야하기 때문에 해시 가능성은 호출하지 않고 쉽게 감지 할 수 없습니다 . 2) 해시 가능성은 불변성을 보장하지는 않습니다-변경 가능한 해시 가능한 객체의 예를 쉽게 만들 수 있습니다. 3) 파이썬의 대부분의 컨테이너와 마찬가지로 튜플은 기본 객체에 대한 참조 만 가지고 있습니다. 튜플은 컨테이너를 검사하고 추론 할 의무가 없습니다.
Raymond Hettinger

171

튜플 에는 목록, 문자열 또는 숫자가 포함되어 있지 않기 때문 입니다. 여기에는 다른 객체에 대한 참조가 포함 됩니다 . 1 튜플에 포함 된 참조 시퀀스를 변경할 수 없다고해서 해당 참조와 연관된 객체를 변경할 수는 없습니다. 2

1. 객체, 값 및 유형 (두 번째 단락에서 마지막 단락 참조)
2. 표준 유형 계층 구조 ( "불변 시퀀스"참조)


8
질문에 모호함이 있습니다. 이 답변 은 튜플에 가변 객체가 포함될 수있는 이유를 충분히 설명 합니다. 튜플이 가변 객체를 포함 하도록 설계된 이유는 설명하지 않습니다 . 나는 후자가 더 적절한 질문이라고 생각합니다.
senderle

16

우선, "불변"이라는 단어는 다른 사람들에게 많은 다른 것을 의미 할 수 있습니다. 특히 Eric Lippert가 블로그 게시물 에서 불변성을 분류 한 방식이 마음에 듭니다 . 그는 다음과 같은 종류의 불변성을 나열합니다.

  • Realio-trulio 불변성
  • 1 회 기록 불변성
  • 아이스 불변성
  • 얕은 대 불변성
  • 불변 외관
  • 관찰 불변성

이것들은 더 많은 종류의 불변성을 만들기 위해 다양한 방식으로 결합 될 수 있으며 더 많이 존재합니다. 불변 개체는 다른 불변 개체 만 포함 할 수있는 깊은 (전 이적) 불변에 관심이있는 것처럼 보입니다.

이것의 핵심은 깊은 불변성은 많은 종류의 불변성의 하나 일 뿐이라는 것입니다. "불변의"이라는 개념이 아마도 다른 사람의 "불변의"개념과 다름을 알고있는 한, 당신이 선호하는 어떤 종류를 채택 할 수 있습니다.


파이썬 튜플에는 어떤 종류의 불변성이 있습니까?
qazwsx

3
파이썬 튜플은 얕은 (일명 비 전 이적) 불변성을 가지고 있습니다.
Ken Wayne VanderLinde

16

내가 이해함에 따라이 질문은 디자인 결정에 대한 질문으로 다시 표현해야합니다. 파이썬 디자이너는 왜 변경 가능한 객체를 포함 할 수있는 불변 시퀀스 유형을 만들었습니까?

이 질문에 대답하기 위해, 우리는 목적에 대해 생각해야 튜플 제공 : 그들은 같은 역할을 빠른 , 범용 시퀀스를. 이를 염두에두고 왜 튜플을 변경할 수 없지만 변경 가능한 객체를 포함 할 수 있는지가 분명해집니다. 재치 :

  1. 튜플은 빠르고 메모리 효율적입니다. 튜플 은 변경 불가능하므로 목록보다 생성 속도빠릅니다 . 불변성은 튜플을 상수로 만들어 상수 폴딩을 사용하여로드 할 수 있음을 의미합니다 . 또한 초과 할당 등이 필요하지 않기 때문에 생성 속도가 빠르고 효율적 입니다. 임의 항목 액세스 목록보다 약간 느리지 만 포장 풀기 (적어도 내 컴퓨터에서는)보다 약간 빠릅니다. 튜플이 변경 가능하면 이러한 튜플은 그렇게 빠르지 않습니다.

  2. 튜플은 범용입니다 . 튜플은 모든 종류의 객체를 포함 할 수 있어야합니다. 가변 길이 인수 목록 과 같은 기능을 (빠르게) 수행하는 데 사용됩니다 ( *함수 정의 의 연산자를 통해 ). 튜플이 변경 가능한 객체를 보유 할 수 없으면 이와 같은 것에 쓸모가 없습니다. 파이썬은 목록을 사용해야 할 것인데, 아마도 목록이 느려질 것이고 메모리 효율이 떨어질 것입니다.

따라서, 목적을 달성하기 위해 튜플 변경 불가능해야하지만 변경 가능한 객체도 포함 할 수 있어야합니다. 파이썬의 디자이너가 "포함하는"모든 객체가 불변 인 것을 보장하는 불변의 객체를 만들고자한다면, 세 번째 시퀀스 유형을 만들어야합니다. 이득은 추가 복잡성에 가치가 없습니다.


12

id항목을 변경할 수 없습니다 . 따라서 항상 같은 항목이 포함됩니다.

$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368

위의 예제 중 가장 적합한 데모입니다. 튜플에는 변경 가능한 구성 요소가 하나만 있으면 전체 튜플을 해시 할 수 없지만 변경되지 않는 객체에 대한 참조가 있습니다.
piepi

5

여기 사지에 나가서 여기에 관련된 부분은이 목록의 내용 또는 개체의 상태를 변경할 수있는 반면, 튜플에 포함하는 것을 말할 것이다, 당신은하지 변화는 무엇인가 할 수 있다는 객체 또는 목록이 있습니다. 비어있는 경우에도 목록 [3]에 의존하는 것이 있다면, 이것이 유용하다는 것을 알 수 있습니다.


3

한 가지 이유는 파이썬에서 가변 유형을 불변 유형으로 변환하는 일반적인 방법이 없기 때문입니다 (거부 된 PEP 351 및 거부 된 이유에 대한 링크 된 토론 참조). 따라서 사용자가 만든 해시 불가능 개체를 포함하여 이러한 제한이있는 경우 다양한 유형의 개체를 튜플에 넣을 수 없습니다.

사전과 세트에 이러한 제한이있는 유일한 이유는 오브젝트가 내부적으로 해시 테이블로 구현되므로 오브젝트를 해시 가능해야하기 때문입니다. 그러나, 아이러니하게도, 사전 및 세트 자체는 참고 하지 불변 (또는 해쉬). 튜플은 객체의 해시를 사용하지 않으므로 변경 가능성은 중요하지 않습니다.


2

튜플은 튜플 자체가 확장 또는 축소 할 수없고 자체 포함 된 모든 항목이 변경 불가능하다는 의미에서 변경할 수 없습니다. 그렇지 않으면 튜플이 둔해집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.