들어가며
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!
x = 10
print(id(x)) # 객체의 메모리 주소(id)
y = x
print(id(y)) # 같은 객체 주소
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
'language > python' 카테고리의 다른 글
클래스, 상속, dunder 메서드 – Python 객체지향 기초 정리 (0) | 2025.04.19 |
---|---|
함수, 매개변수, *args, **kwargs, 스코프, 클로저, 데코레이터 – Python 함수 구조 정리 (0) | 2025.04.19 |
조건문, 반복문, 리스트 컴프리헨션 – Python 제어 흐름 완전 정복 (0) | 2025.04.19 |
리스트, 튜플, 딕셔너리, 셋 – Python 핵심 자료구조 비교와 활용 (0) | 2025.04.19 |
Python 언어의 철학과 특징 – 왜 많은 개발자가 선택하는가? (0) | 2025.04.19 |
댓글