상세 컨텐츠

본문 제목

[ Python 기초 문법 ] - 자료형의 값을 저장하는 공간, 변수

Language/Python

by bing_su 2023. 8. 6. 11:25

본문

반응형
SMALL

이번 게시글에서는 변수에 대해 설명하려고 한다. 최대한 쉽게 설명해 보려고 노력하겠지만, 프로그래밍 초보자가 바로 이해하기에는 어려울 수 있는 내용이니 여러 번 읽기를 바랍니다. 물론 이 내용들은 파이썬에 대해 공부하다 보면 자연스럽게 녹아들 내용이기도 해서 제대로 알아두는 편이 좋을 거라고 생각함.

[ 변수(Variable)의 정의와 변수 선언 ]

변수란 말 그대로 '상황에 따라 변할 수 있는 값'이다. 프로그램에서 변수는 값을 저장할 수 있는 메모리 공간에 붙여진 이름이다. 쉽게 말하면 특정 값을 담는 '상자'라고 생각하면 된다.

<< 변수와 메모리 구조 >>

해당 설명은 비전공자들에게 조금 어려울 수 있습니다. 최대한 쉽게는 써 보겠지만, 이해가 잘 안 가시더라도 '그렇구나' 정도로 생각하시고 넘어가시면 될 것 같습니다. (완전히 체화하려고 애쓰지 않아도 된다는 뜻)

 

우리는 특정 프로그램을 설계하면서 다양한 데이터를 사용한다. 이 데이터는 컴퓨터의 메모리 공간에 저장되며, 저장된 값은 여러 가지 컴퓨터가 수행하는 연산에 의해 변경될 수도 있다. 이렇게 변할 수 있는 값은 모두 변수인 것이다.

 

컴퓨터에 내장된 메모리에는 각각의 정확한 위치를 식별하기 위한 고유한 주소(address)가 존재한다. (집 주소와 비슷한 개념이라고 생각하시면 됨.) 변수는 기본적으로 메모리의 주소를 기억하여 가리키는 역할을 한다. 따라서 프로그램 상에서 변수를 참조(reference)를 하면, 해당 주소에 저장된 데이터를 참조하게 된다. 참조의 의미를 조금 쉽게 풀어쓴 말은 아래의 접은 글과 같다. 이해가 잘 안 되시는 분들을 위해 적었습니다! 필요 없으시면 넘기셔도 됨.

더보기

참조는 쉽게 말해서 컴퓨터에서 바로 가기(symbolic link)를 만드는 것과 비슷하다고 생각하면 된다. 심볼릭 링크를 통해서 만든 파일은 원본 파일에 대한 주소 값을 가진다. (우편 번호가 실제 집 주소를 담고 있는 것과 비슷하다고 보시면 됨.) 누군가 심볼릭 링크를 클릭하면 컴퓨터는 해당 링크에 저장된 원본 파일의 주소를 참조해서, 원본 파일의 위치를 알아내고 원본 파일에 대한 작업을 수행할 수 있게 된다. 이를 원본 파일을 그대로 복제하는 것이 아닌, 참조(reference)한다고 표현한다.

또한 원본 파일에 대한 심볼릭 링크를 만들었을 때, 원본을 수정하면 심볼릭 링크에도 그 내용이 실시간으로 반영된다. 마찬가지로 특정 메모리 주소 내에 있는 데이터 값을 수정하면 해당 주소를 참조하는 변수 값도 변경되는 것이다.

아래 그림은 선언된 변수가 메모리에 어떻게 저장되는지를 보여준다.

메모리에 저장된 데이터의 해석

위의 그림을 설명하기 이전에 비트(bit)바이트(byte) 개념을 먼저 설명하려고 한다.

※ 비트(bit)와 바이트(byte)

컴퓨터는 모든 데이터를 이진수로 표현하고 처리한다.

비트(bit)는 컴퓨터가 데이터를 처리하기 위한 최소의 단위다. 하나의 비트에는 0 또는 1, 즉, 이진수 값 하나만을 저장할 수 있다. 이와 같은 비트가 8개 모여서 구성되면, 하나의 문자를 표현할 수 있고 이것이 바로 바이트(byte)가 된다.

※ 변수와 메모리 구조

다시 위의 그림을 보자. 하나의 메모리 공간에는 8개의 비트로 구성된 1byte의 데이터가 저장된다. 메모리의 주소는 1byte씩 늘어나고, 낮은 주소에서 높은 주소로 데이터가 저장된다. 위의 그림에서는 변수가 0x10부터 0x13까지 4개의 메모리 공간에 존재한다. 따라서 해당 변수에는 4byte의 데이터가 저장되어 있다고 볼 수 있다.

 

앞서, 변수는 메모리 주소를 가리키는 역할을 한다고 배웠다. 이때 변수는 첫 번째 메모리 주소(그림에서는 0x10에 해당)만을 가리킨다. 이 때문에 변수는 데이터가 저장된 메모리의 주소뿐만 아니라, 저장된 데이터의 길이와 형태에 관한 정보도 함께 기억하게 된다. (그렇게 해야 해당 변수를 사용할 때 데이터를 완전히 올바르게 참조할 수 있겠죠?)

<< 변수의 선언 >>

>>> a = 10

위와 같은 코드를 살펴보자. 우리는 앞서 다룬 자료형에서 이미 이러한 방식으로 변수를 사용해 왔다. 프로그램을 짤 때는 변수를 사용하기 전에 반드시 해당 변수를 저장하기 위한 메모리 공간을 할당받아야 한다. 이렇게 해당 변수를 위한 메모리 공간을 할당받는 행위를 '변수를 선언한다'라고 표현한다. 변수를 선언할 때는 '=(assignment)' 기호를 사용한다. (우리가 흔히 수학 시간에 배운 '=(equal)' 기호와는 살짝 다른 의미다. 등호는 추후 다루겠지만, 프로그래밍에서는 '=='로 표시한다.)

 

이를 조금 쉬운 말로 설명하기 위해 위의 코드를 살펴보자. 해당 코드는 '10이라는 값을 a라고 하는 상자(변수)에 담아줘!'라는 의미로 해석하면 된다. 즉, a 변수가 가리키는 메모리의 주소에 10의 값이 저장되는 것이다.

>>> a = 10  # 변수 a의 선언
>>> id(a)  # 변수 a가 가리키는 메모리 주소를 확인하는 함수 id() 사용
2474248071760  # 변수 a가 가리키는 주소 값

파이썬에서 a 변수가 가리키는 주소는 위와 같이 확인할 수 있다. id 함수는 변수가 가리키는 객체의 주소 값을 반환하는 파이썬 내장 함수다. (객체에 관련해서는 추후에 더 자세히 다룰 예정) 쉽게 말하면 위의 코드를 통해 변수 a가 가리키는 10의 주소 값은 2474248071760임을 알 수 있다. 

[ 여러 개의 변수를 한 번에 선언 ]

- 튜플을 이용하여 각 값을 할당

>>> a, b = ('python', 'life')
>>> (a, b) = 'python', 'life'

위 예문처럼 튜플로 a, b의 값을 대입할 수 있다. 참고로 말하자면 두 코드 모드 동일한 의미다. 앞서 다룬 튜플 자료형에서도 설명했지만 튜플은 괄호를 생략해도 되기 때문이다.

- 리스트를 이용하여 각 값을 할당

>>> [a, b] = ['python', 'life']

- 여러 개의 변수에 동일한 값을 할당

>>> a = b = 10

- 아무런 값이 없는, 비어 있는 변수를 만들고 싶을 때

>>> a = None  # a는 아무런 값을 가지지 않음

위의 방법을 사용하여 두 변수의 값을 바꾸는 실습을 진행하자.

>>> a = 3  # a 변수에 3을 대입
>>> b = 5  # b 변수에 5를 대입
>>> a, b = b, a  # (a, b) = (b, a)와 동일 의미. 두 변수의 값을 바꿈.
>>> a
5
>>> b
3

처음에는 a에는 3, b에는 값 5가 대입되어 있다. a, b = b, a 문장을 수행한 후에는 그 값이 서로 바뀐다.

[ 변수 이름 규칙 ]

변수를 선언할 때 변수의 이름은 마음대로 지으면 된다. 하지만 여기에도 몇 가지 지켜야 할 규칙이 있다.

  • _(underbar) 또는 영문자로 시작해야 한다.
  • 숫자로 시작할 수 없다.
  • 특수문자(+, -, % 등)는 사용할 수 없다.
  • 변수 이름에 space나 tab 등의 공백을 사용할 수 없다. (보통 _로 이어줌)
  • 파이썬에 존재하는 예약어(이미 사용 중인 이름. if나 while 등)를 사용할 수 없다.
    파이썬에 존재하는 예약어는 아래의 코드로 확인할 수 있다.
import keyword
print(keyword.kwlist)

[ 리스트의 복사 ]

앞서 다뤘던 변수의 값을 서로 바꾸는 것에서 조금 더 심화된 내용이다. 리스트 자료형을 '복사(copy)'하는 것에 대해 다루려고 한다. 아래의 예시를 통해 자세히 살펴보자.

>>> a = [1, 2, 3]  # a 변수를 리스트로 선언
>>> b = a  # b 변수에 a 변수를 대입

b 변수에 a 변수를 대입하면 b는 a와 완전히 동일해진다. 즉, [1, 2, 3] 리스트를 참조하는 변수가 a 변수 하나에서 b 변수가 추가되어 둘로 늘어나게 되는 것이다. 이를 그림으로 나타내면 아래와 같다.

a 변수와 b 변수의 메모리 참조

즉, 실제 리스트는 하나만 존재하고 해당 리스트가 존재하는 메모리를 a와 b 변수 두가지 이름으로 가리키는 것이다.

>>> id(a)  # 변수 a가 가리키는 메모리 주소 반환
2406915438656
>> id(b)  # 변수 b가 가리키는 메모리 주소 반환
2406915438656

a 변수와 b 변수가 가리키는 주소가 동일함을 확인할 수 있다. 즉, a와 b는 동일한 메모리를 가리키고 있다는 것이다.

>>> a[1] = 4  # a 리스트에서 두 번째 요소를 값 4로 바꿈.
>>> a  # a 변수 확인
[1, 4, 3]
>>> b  # b 변수 확인
[1, 4, 3]

이번에는 a 리스트에서 두 번째 요소(index=1)를 값 4로 바꿨다. 이때 a만 바뀌는 것이 아니라 b도 똑같이 바뀌는 것을 확인할 수 있다. 앞서 살펴본 바와 같이 a, b는 모두 동일한 메모리에 있는 리스트를 가리키고 있기 때문이다.

 

그렇다면 b 변수를 생성할 때 a 변수의 값을 가져오면서 a와는 다른 메모리 주소를 가리키도록 만들 수는 없을까? 즉, a의 값을 수정하더라도 b가 바뀌지 않도록 할 수 있을까? 이때 사용하는 것이 얕은 복사(shallow copy)이며, 아래의 두 가지 방법으로 해당 방식을 사용할 수 있다.

1. [:] 사용

첫 번째 방법은 리스트 전체를 슬라이싱하는 [:]를 이용하여 복사하는 것이다.

>>> a = [1, 2, 3]  # a 변수를 리스트로 선언
>>> b = a[:]  # b에 a 리스트 전체를 슬라이싱한 리스트를 대입
>>> a[1] = 4  # a 리스트에서 두 번째 요소를 값 4로 바꿈.
>>> a  # a 변수 확인
[1, 4, 3]
>>> b  # b 변수 확인
[1, 2, 3]

위와 같이 a 리스트 값을 바꾸더라도 b 리스트에는 영향을 끼치지 않음을 확인할 수 있다.

2. copy 모듈의 copy 함수 사용

두 번째 방법은 파이썬 copy 모듈의 copy 함수를 이용하는 것이다. 파이썬 모듈에 대한 자세한 내용은 추후에 설명할 것이니 일단 지금은 '이런 게 있구나' 정도로 넘어가자.

# copy 모듈을 사용하기 위해 import 명령어 사용
# copy 라이브러리 이름을 사용하지 않고 함수 이름만 간단히 사용하기 위해 from 명령어 사용
>>> from copy import copy
>>> a = [1, 2, 3]  # a 변수를 리스트로 선언
>>> b = copy(a)  # copy 함수를 이용하여 a[:]과 동일한 방식으로 리스트를 복사
>>> a[1] = 4  # a 리스트에서 두 번째 요소를 값 4로 바꿈
>>> a  # a 변수 확인
[1, 4, 3]
>>> b  # b 변수 확인
[1, 2, 3]

1번 방식과 똑같이 a 리스트 값을 바꾸더라도 b 리스트에는 영향을 끼치지 않는다.

from copy import copy와 같이 모듈을 사용하는 방법에 대해서는 추후에 다룰 예정이니 잘 모르겠다면 지금은 그냥 넘어가도 무방함. 그리고 copy 함수는 a[:]와 동일한 방식으로 동작한다고 이해하시면 됨.

반응형
LIST

관련글 더보기

댓글 영역