본문 바로가기
language/python

변수와 자료형, 그리고 Python의 동적 타이핑 이해하기

by 죄니안죄니 2025. 4. 19.

들어가며

Python은 타입 선언이 필요 없는 동적 타이핑 언어입니다.
처음 Python을 접할 때 가장 크게 느껴지는 특징 중 하나는 int, String, boolean 등을 선언하지 않아도 된다는 점입니다.

이 글에서는 language/python 카테고리의 첫 번째 주제로, Python의 변수 선언, 자료형, 동적 바인딩의 원리를 예제 중심으로 쉽게 설명합니다.

 

 

 

변수란 무엇인가?

변수란 데이터를 저장할 수 있는 이름을 가진 메모리 공간입니다. Python에서는 변수 선언 시 별도의 타입을 지정하지 않아도 됩니다.

x = 10       # 정수 int 클래스의 객체
print(type(x)) # <class 'int'>

name = "Tom" # 문자열 str 클래스의 객체
print(type("tommy")) # <class 'str'>

is_admin = True  # 불리언 bool 클래스의 객체

def my_func(): pass
print(type(my_func)) # <class 'function'> 함수도 인스턴스. 함수를 인자로 받을 수 있음 . 값처럼 취급.
def run_twice(f):
  f()
  f()
run_twice(my_func)

class MyClass: pass
print(type(MyClass)) # <class 'type'> 클래스도 인스턴스

print(type(len)) # <class 'builtin_function_or_method'> 모듈도 인스턴스
  • 변수는 곧 객체에 대한 참조(reference)
  • Python에서는 모든 것이 객체이며, 변수는 해당 객체를 가리킴

1. 속성과 메서드를 가질 수 있는 클래스의 인스턴스라서 바로 함수나 속성을 불러올 수 있다는 말

2. 커스터마이징 상속 오버라이딩이 쉽다는 말

3. 동적으로 타입 체크, 송석 추가, 삭제 가능

4. 함수도 객체이므로 함수 자체를 인자로 넘기거나 변수에 할당 가능

def greet():
    print("Hi!")

a = greet  # 함수도 변수에 할당 가능
a()        # Hi!

 

그래서 값을 복사하는 게 아니라 참조(포인터) 자바는 primitive type이라고 해서 값자체가 변수에서 복사되는 것과 차이가 있습니다. 
x = 10
print(id(x))  # 객체의 메모리 주소(id)

y = x
print(id(y))  # 같은 객체 주소
파이썬에서는 인스턴스 변수는 포인터니까 그 자체로 하나의 값이자 객체이다. 속성과 메서드를 갖게 된다. 
자바에서 변수가 기본타입은 값,객체는 참조 역할이라고 할 때 쓰는 '값'과 다른 의미이다.
자바에서는 변수 자체가 그 값을 메모리에 직접 갖고 있다는 뜻이고, 10, 20이 값이 독립적 공간에 별도 보관, 값만 복사.

 

int a = 10;
int b = a; // 값 복사
b = 20;

System.out.println(a); // 10​
a = 10
b = a // 포인터 복사
b = 20

print(a)  # 10

 

파이썬이 동일하게 동작하는 것처럼 보이지만 원리가 다름. 모든 객체가 값이라 포인터 처럼 가르키는 상태이지만 불변객체를 새로 할당하는 경우 b의 참조 주소가 10에서 끊기고, 20을 가르키는 주소로 바뀐것임. 값 복사가 아님. 

즉 불변 객체는 객체 수정이 불가능하다. 

분류 예시 설명
Immutable (불변) int, float, str, tuple, bool, frozenset 객체를 수정할 수 없음
Mutable (가변) list, dict, set, bytearray, 사용자 정의 클래스 등 객체를 수정할 수 있음

 

 

 

자바는 불변 가변이 이미 타입수준 (primitive/object) 으로 분류를 해서 불변여부는 타입에 따라 결정되지만,

파이썬은 모든 객체는 참조고,값이라 기본타입이 없는 대신 객체 특성 자체가 mutable/immutable 이 구분이 나뉘게 됩니다. 

이 차이를 알아야 다음이 이해돼요:

  • 리스트를 함수 인자로 넘겼을 때 원본이 바뀌는 이유
  • 딕셔너리 키로 쓸 수 있는 자료형은 왜 immutable만 되는지
  • 튜플은 왜 안전하고 리스트는 조심해야 하는지
x = [1, 2]
print(id(x))
x.append(3)
print(id(x))  # 같은 ID (가변)

y = "hello"
print(id(y))
y += " world"
print(id(y))  # 다른 ID (불변)

id() 는 메모리주소값을 볼 수 있음. 불변 객체의 경우 변경을 가하는 행위시 별도의 객체를 참조하도록 변경됨. 

a is b 는 id(a) == id(b)와 완전히 동일함. ==는 값(내용)이 같은지 비교(eq()와 동일)하는거라 is를 합쳐야 객체(참조)를 비교할 수 있음. 

리터럴 방식이나 + 연산자에 의한 할당은 새로운 객체를 만들어서 할당하게 되니까 id가 변경됨

참고로, 자바는 == 연산자는 기본형, 객체 모두 사용할 수 있고, 참조값(주소)을 비교함 (파이썬 is)

자바의 .equals()은 객체에만 사용할 수 있고 내용(논리적 동등함)을 비교함 (파이썬 ==)


Python의 자료형 (기본 타입)

자료형 예시
int (정수) x = 10
float (실수) pi = 3.14
str (문자열) s = "hello"
bool (논리형) flag = True
list (리스트) arr = [1, 2, 3]
tuple (튜플) t = (1, 2)
dict (딕셔너리) d = {"a": 1}
set (집합) s = {1, 2, 3}
NoneType x = None

이 모든 타입도 사실상 class로 정의된 객체입니다. 예: type(10) → <class 'int'>

 

자바는 정적 타이핑, primitive 타입과 참조타입 분리되어 있고 파이썬은 동적 파이핑, 모든것이 객체라는 차이가 있습니다. 

자바와 파이썬은 설계방식부터 자료형까지 다르게 구성됩니다. 설계 철학이 다르기 때문에 특히 가변/불변 함수, null/None, 숫자 범위 다루는 데 주의해야합니다.

파이썬 자료형 자바 대응 자료형 차이점 설명
int int, long, BigInteger 파이썬은 무한 정수 크기, 자바는 int(32bit), long(64bit) 제한
float float, double 파이썬은 IEEE 754 double 기반 (자바의 double과 유사)
str String 거의 유사하지만, 파이썬은 가변 길이 유니코드 지원 더 자유로움
bool boolean 같음 (True/False ↔ true/false)
list ArrayList, List<T> 파이썬은 동적 타입 리스트, 자바는 제네릭 기반 고정 타입
tuple 없음 (불변 리스트 비슷한 구조 없음) 파이썬만의 불변 순서 구조. Java에는 명확히 없음(별도로 구현해야 함)
dict HashMap<K,V>, Map<K,V> 개념은 유사하지만 구현 방식 다름
set HashSet<T>, Set<T> 거의 유사
None null 거의 유사하지만 파이썬의 None은 객체임
function Function<T, R> (람다) 파이썬은 함수도 객체, 자바는 함수형 인터페이스로 제한적 구현(람다식으로 유사하게 흉내 가능 Java 8 이상)
Runnable r = () -> System.out.println("hi");
r.run();
class class 둘 다 객체지향이지만 문법과 상속 구조가 많이 다름
bytes, bytearray byte[], ByteBuffer 둘 다 바이트 처리 가능하나 API 구조 다름
complex 없음 (Complex 직접 구현 필요) 파이썬은 내장 지원, 자바는 외부 라이브러리 필요
range IntStream, for loop 파이썬은 내부적으로 range 객체 생성, 자바는 단순 반복문
object Object 둘 다 모든 클래스의 최상위 조상

동적 타이핑이란?

Python은 변수 선언 시 타입을 명시하지 않고, 실행 중에 타입이 결정되는 방식입니다.

x = 5       # x는 int
x = "hi"    # 이제 x는 str
  • 변수 x는 객체를 참조하는 역할일 뿐, 그 자체가 고정된 타입을 가지지는 않음
  • 같은 이름의 변수라도 다른 타입의 객체를 참조할 수 있음

✅ 타입 확인하기

x = 3.14
print(type(x))  # <class 'float'>

✅ 타입 변환도 자유로움

num = int("42")     # 문자열 → 정수
s = str(100)        # 정수 → 문자열
is_true = bool(1)   # 1 → True

변수 참조와 메모리 구조 간단 이해

x = 100
  • 숫자 100은 int 객체로 Heap에 생성
  • 변수 x는 그 객체를 Stack에서 참조
x = 100
y = x
  • x, y 모두 같은 int(100) 객체를 참조 (참조 카운트 증가)

id(x)id(y)는 같음 (객체 주소 확인)


요약 정리

  • Python 변수는 타입을 선언하지 않으며, 객체 참조를 통해 동작함
  • 변수는 객체의 주소값(참조)을 담는 이름일 뿐
  • 동적 타이핑으로 인해 변수는 다양한 타입의 객체를 자유롭게 참조 가능
  • 하지만 타입 안정성/예측성 측면에서는 주의가 필요함

다음 글 예고

📂 language/python 카테고리 다음 글에서는:

  • 리스트, 튜플, 딕셔너리 등 Python의 핵심 내장 자료구조 비교
  • 불변(immutable) vs 가변(mutable)의 차이와 주의점
  • is, == 차이와 참조 기반 비교 개념

등을 이어서 다룰 예정입니다.

 


📌
이전 글 보러가기
👉 Python 언어의 철학과 특징 – 왜 많은 개발자가 선택하는가?
📌 
다음 글 미리보기
👉 리스트, 튜플, 딕셔너리, 셋의 차이와 내부동작, 고급 사용법

📚 언어 Python 시리즈 전체 보기
👉 https://jobreview.tistory.com/category/language/python

 

댓글