본문 바로가기

진리는어디에/Python

[Python] 변수 #1 소개

이번 포스트에서는 파이썬 언어의 변수에 대해 살펴 보도록 한다. 간단하게 변수의 선언과 사용에서 시작하여 변수의 메모리 구조와 형태에 대해 좀더 깊게 알아 보도록 할 것이다.

목차

  1. >> 파이썬 변수의 소개
  2. 변수의 타입
  3. 변수의 다양한 정보 확인
  4. ctype 모듈을 활용한 변수의 정보 확인
  5. == 와 is 연산자
  6. mutable 변수와 immutable 변수
  7. 변수의 삭제
  8. 파이썬 정수는 Overflow가 없다?

파이썬 변수의 선언과 사용

프로그래밍 언어에서 "변수"란 정보를 저장할 수 있는 공간(메모리)에 이름을 붙인 것이다. 메모리에 우리가 프로그래밍에서 사용하는 값을 저장하고 변수의 선언 시 붙여준 이름을 통해 그 값에 접근하여 읽고 쓸 수 있도록 해준다. C/C++, C#, Java와 같은 언어와는 다르게 파이썬에서는 변수의 선언 과정이 없으며, 아래와 같이 단순히 변수에 값을 대입하는 것으로 변수를 생성 한다.

n1 = 10 # n1 변수에 10이라는 값을 저장함
n2 = n1 # n2 변수에 n1이 가지고 있는 값을 저장함. 
n2 = 20 # 이제부터는 n2는 20라는 값을 가지고 있다.
n1 = "abcd" # n1에 숫자가 아닌 문자열도 저장하게 할 수 있다.

print(n1) # n1이라는 변수의 이름으로 변수가 가지고 있는 값을 가져와 출력 할 수 있다.
print(n2)

1 부터 4라인 처럼 변수에 값을 저장 후, 6, 7라인 처럼 변수의 이름(n1, n2)을 통해 해당 변수가 가진 값을 가져다 사용 할 수 있다.

정리하면 :

  • 파이썬에선 변수의 선언 없이 사용 된다.
  • 변수는 정수형이든 문자열이든 가리지 않고 모두 사용 가능하다.
  • 변수의 이름을 통해 해당 값을 사용 할 수 있다.

정도로 요약 된다. 여기까지가 파이썬 변수의 기본이다.

"변수에 값을 넣고, 사용한다." 아주 간단하고 명료한 개념이다. 여기까지만 알면 r파이썬 프로그래밍을 할 때 변수 관련된 기본적인 사항은 모두 알게 되었다. 그럼 이제는 기본을 조금 넘어 변수가 생성 될 때 파이썬 내부적으로 어떠한 일이 일어나는지 알아 보도록하자.

파이썬 변수의 특징

다시 위 예제의 1라인을 살펴 보자. n1 = 10이라고 작성되어 있다. 위 처럼 변수에 값을 대입하는 순간 파이썬은 메모리에 '10'이라는 값을 가지고 있는 객체를 생성하고, n1변수가 해당 객체를 가리키게 한다. 이렇게 우리는 'n1'이라는 이름을 통해 해당 객체에 접근할 수 있게 되는 것이다.

앞에서 설명을 간단하게 하기 위해 n1변수가 10이라는 값을 가진다는 표현을 썼었다. 하지만 정확하게 말하면 이는 거짓이다. n1변수는 10이라는 값을 가지고 있는 객체를 가리킨다가 맞다.

10이라는 값을 가진 객체와 변수 n1

2라인의 'n2 = n1'라는 것은 n1변수가 가리키는 객체를 n2도 똑같이 가리키겠다는 의미다.

동일한 객체를 가리키는 n1과 n2

위 n1, n2를 통해 우리는 파이썬에서의 변수는 특정 값을 가지고 있는 객체를 가리키는 '참조자' 역할을 한다는 것을 알수 있다. C/C++이나 C#, Java 프로그램 언어 경험이 있는 분이라면 포인터 또는 참조 변수와 비슷하다고 이해하면 된다.

이 상태에서 3라인의 'n2 = 20'을 수행하게 되면 메모리 어딘가에 '20'이라는 값을 가진 객체가 생성되고, n2는 이제 부터 새로 생성된 객체를 가리킨다.

새로 생성된 20이란 값을 가지고 있는 n2

4라인의 n1 = 'abcd'를 수행하면 다시 abcd라는 값을 가지고 있는 객체를 메모리 어딘가에 생성하고 n1은 새로운 객체를 가리킨다.

C/C++, C#, Java와 같이 강력한 타입 제한을 가진 언어에선 다른 타입의 값을 저장하려 하면 컴파일 에러를 발생 시키겠지만 파이썬의 '변수'는 모든 타입의 객체를 가리킬 수 있기 때문에 위와 같은 연산이 가능하다.

파이썬 변수의 메모리 구조

앞에서 파이썬 변수가 생성 될 때 어떠한 일이 일어나는지 살펴 보았다. 지금 부터는 조금 더 깊이들어가 파이썬 변수의 메모리 구조에 대해서 살펴 보도록 하자.

파이썬 변수는 값 자체를 가지고 있는 것이 아니라 값을 저장하고 있는 객체를 참조 하고 있다고 이야기 했었다. 다시 처음의 예제를 살펴 보자. 

n1 = 10 # n1은 10이라는 정수 값을 가진 객체를 가리킨다.
n2 = n1 # n2는 n1이 가리키는 객체를 같이 가리킨다.

위와 같이 n1, n2가 정의 되어 있다면 n1과 n2는 동일한 객체를 가리키게 된다고 했다.

동일한 객체를 가리키는 n1과 n2

하지만 n1, n2가 가리키는 객체는 단순히 10이라는 값만을 가진게 아니라 여러 추가 정보들을 가지고 있다. 조금만 더 안으로 들어가 살펴 보면 변수 값을 가진 객체는 대충 아래와 비슷한 구조를 가지고 있다.

  • 먼저 객체는 라이프 사이클을 관리하기 위해 자신을 가리키고 있는 변수들의 참조 계수를 저장한다(ob_refcnt).
    객체를 가리키는 변수가 늘어 날수록 참조 계수도 증가하고, 줄어들수록 참조 계수도 감소하여 결국 참조 계수가 0이되면 객체가 메모리에서 해제 된다.
  • 객체는 자신이 가지고 있는 타입에 대한 정보를 가지고 있는 또 다른 객체를 가리키는 변수를 내부적으로 가진다(ob_type). 위 예제에서는 10은 정수이므로 정수 타입에 대한 정보를 담은 객체를 가리키는 내부 변수가 있다고 이해하면 된다.
n1 = 10
n2 = n1
n3 = 20 # n3는 다른 새로운 객체를 가리킨다. 하지만..

변수 n3가 추가 되었다. n3은 n1, n2와 다른 값을 가지고 있다. 이런 경우 파이썬은 메모리 어딘가에 새로운 객체를 생성한 뒤 n3가 해당 객체를 가리키게 한다고 이미 설명했다. 여기서 한가지 더 추가 되는 것이있다.

n3 객체는 정수형 변수이므로, 방금 새로 생성된 20을 가지고 있는 객체 또한 이전에 생성된 10을 가지고 있는 객체와 동일한 타입 정보를 가리킨다는 것이다. 그림으로 설명하면 아래와 같다.

이번에는 float 타입의 변수가 추가 되는 경우를 살펴 보자.

n1 = 10
n2 = n1
n3 = 20
f1 = 3.14 # 정수가 아닌 실수 타입의 변수

너무 여러번 반복해서 설명해서 지겨운 감이 있지만, 파이썬은 3.14의 실수(float 또는 double) 타입을 가지는 객체를 만들고 변수 f1이 해당 객체를 가리키도록 한다. 이번에 다른점은 새로 생성된 객체는 정수형이 아닌 실수형이므로  ob_type은 다른 타입 정보 객체를 가리킨다는 것이다.

이렇게 네 줄의 코드가 실행 되었을 때 메모리 구성의 대략 위처럼 구성 된다.

PyObject

위 그림을 살펴 보면 정수형 객체와 실수형 객체의 형태가 다른 것이 보인다. 하지만 모든 객체들이 공통적으로 가지고 있는 부분 또한 있다(녹색으로 표현된 박스). 모든 파이썬 객체들은 PyObject라는 객체(녹색 부분)에서 파생되며, 파이썬 변수들은 PyObject를 가리킬수 있도록 만들여졌다.

n1 = 10
n2 = n1
n3 = 20
f1 = 3.14 # 정수가 아닌 실수 타입의 변수

n1 = f1

6라인과 같이 정수형 타입의 변수에 float 타입의 변수를 대입하게 되면 단순히 참조를 변경하기만 하면 된다.

마치며

이번 포스트를 통해 기억하고 넘어가야 하는 것들에 대해 정리해보도록 한다.

  • n1 = 10 라고 했을 때 메모리 구조.
    값을 가진 객체를 생성하고 변수는 해당 객체를 가리킨다.
  • 모든 객체는 참조 계수(ob_refcnt)로 수명이 관리된다.
  • 모든 타입의 객체는 공통의 특징(PyObject, 참조 계수와 타입 정보)을 가지고 있다.
  • 변수는 모든 종류의 객체를 가리킬 수 있다

이상 파이썬 변수의 선언과 변수의 메모리 구조에 대해 알아 보았다. 다음 장 변수의 타입에서는 파이썬의 표준 타입과 객체들 그리고 그 구조에 대해서 살펴 보도록 하겠다.

부록 1. 같이 보면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!