블록 안에 아무것도 하지 않겠다 는 의미입니다.
Python은 Java와 달리 빈 블록 {} 을 허용하지 않습니다.
Python은 들여쓰기로 블록을 구분하기 때문에, 블록 안에 반드시 뭔가 있어야 합니다.
// Java - 빈 블록 허용
class MyClass {}
void myFunction() {}
# Python - 빈 블록 불가 → SyntaxError 발생
class MyClass:
# 아무것도 없으면 에러!
# pass 로 해결
class MyClass:
pass
def my_function():
pass
if True:
pass
나중에 구현할 예정인 코드 자리를 잡아둘 때 자주 사용합니다.
# 인터페이스처럼 구조만 잡아두기
class Animal:
def speak(self):
pass # 나중에 구현 예정
def move(self):
pass # 나중에 구현 예정
Java의 ArrayList와 유사한 mutable(가변) 자료형입니다.
[] 로 표기하며, 서로 다른 타입의 요소도 함께 담을 수 있습니다.
a = [1, 2, 3]
a.append(4) # [1, 2, 3, 4] - 요소 추가
a + [5, 6] # [1, 2, 3, 4, 5, 6] - 리스트 합치기
a * 2 # [1, 2, 3, 4, 1, 2, 3, 4] - 반복
Java였다면 리스트 합치기에 addAll(), 반복은 루프를 직접 돌려야 했지만
Python은 +, * 연산자로 직관적으로 표현할 수 있습니다.
리스트는 참조 타입이므로 단순 대입은 복사가 아닙니다.
Java의 객체 참조와 동일하게 동작합니다.
a = [1, 2, 3]
b = a # b는 a와 동일한 리스트를 가리킴
b.append(4)
print(a) # [1, 2, 3, 4] - a도 같이 변경됨!
# 진짜 복사를 원한다면
b = a.copy() # shallow copy
b = a[:] # 슬라이싱으로 복사 (Python스러운 방식)
b = list(a) # list() 생성자 활용
() 로 표기하며, immutable(불변) 자료형입니다.
한 번 생성하면 요소를 추가, 수정, 삭제할 수 없습니다.
a = (1, 2, 3)
a[0] = 99 # TypeError: 'tuple' object does not support item assignment
Java의
final List는 참조만 못 바꾸는 것이지만,
Python의 tuple은 내부 요소 자체를 아예 변경할 수 없습니다.
언제 튜플을 쓸까요?
변경되면 안 되는 데이터(좌표, 설정값 등)를 담을 때, 또는 함수에서 여러 값을 반환할 때 자연스럽게 사용됩니다.
point = (10, 20) # 좌표처럼 변하면 안 되는 값
return min(a), max(a) # 함수의 다중 반환값 (내부적으로 tuple)
| List | Tuple | |
|---|---|---|
| 문법 | [1, 2, 3] | (1, 2, 3) |
| 수정 | ✅ 가능 | ❌ 불가능 |
| Java 유사 개념 | ArrayList | 불변 객체 |
Python의 == 와 is 는 전혀 다른 비교를 합니다.
| Python | Java | 설명 |
|---|---|---|
== | .equals() | 값 비교 |
is | == | 객체 동일성 비교 (같은 객체인가?) |
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True - 값이 같음
print(a is b) # False - 서로 다른 객체
None 은 전역에 딱 하나만 존재하는 객체이기 때문에,
값 비교보다 객체 동일성 비교가 더 정확하고 빠릅니다.
a = None
if a is None: # ✅ 권장
pass
if a == None: # 동작하지만 비권장
pass
Python은 -5 ~ 256 사이의 정수를 미리 캐싱해두기 때문에,
해당 범위 안의 숫자는 is 비교가 True 로 나옵니다.
a = 1
b = 1
print(a is b) # True - 캐싱 범위 내
a = 1000
b = 1000
print(a is b) # False - 캐싱 범위 밖, 다른 객체
Java의 Integer 캐싱(-128 ~ 127)과 동일한 개념입니다.
따라서 숫자, 문자열에는 is 를 쓰지 않는 것이 원칙이고,
is 는 None, True, False 비교에만 쓰는 것이 관례입니다.
Java의 삼항연산자 ? : 를 Python에서는 아래와 같이 표현합니다.
# 기본 문법
참일때의_값 if 조건식 else 거짓일때의_값
// Java
String result = x > 5 ? "크다" : "작다";
# Python
result = "크다" if x > 5 else "작다"
Java와 순서가 반대라는 점을 주의하세요.
Java는 조건 ? 참 : 거짓 이지만, Python은 참 if 조건 else 거짓 입니다.
f-string 안에서도 사용할 수 있습니다.
age = 20
print(f"{'성인' if age >= 18 else '미성년자'}") # "성인"
순서가 있는 자료형(list, tuple, string)의 일부를 잘라내는 기법입니다.
Java의 subList(), substring() 을 훨씬 간결하게 표현할 수 있습니다.
[start:end:step]
start: 시작 인덱스 (포함, 기본값 0)end: 끝 인덱스 (미포함, 기본값 len(a))step: 간격 (기본값 1, 생략 가능)end가 미포함이라는 점을 꼭 기억하세요.
a[1:4] 는 index 1, 2, 3 까지이고 4는 포함되지 않습니다.
a = [0, 1, 2, 3, 4]
a[1:4] # [1, 2, 3] - index 1~3 (4 미포함)
a[:3] # [0, 1, 2] - start 생략 → 0부터
a[2:] # [2, 3, 4] - end 생략 → 끝까지
a[:] # [0, 1, 2, 3, 4] - 전체 복사
a[::2] # [0, 2, 4] - 하나씩 건너뜀 (step=2)
a[::-1] # [4, 3, 2, 1, 0] - 역순 (step=-1)
step이 음수이면 역방향으로 순회하기 때문에 기본값이 바뀝니다.
| step > 0 | step < 0 | |
|---|---|---|
| start 기본값 | 0 (처음부터) | len(a) - 1 (끝부터) |
| end 기본값 | len(a) (끝까지) | 처음 요소까지 포함 |
a = [0, 1, 2, 3, 4]
a[::-1] # [4, 3, 2, 1, 0] - 끝에서 처음까지 역순
a[3::-1] # [3, 2, 1, 0] - index 3부터 역순
순서가 있는(sequential) 자료형이면 모두 슬라이싱이 가능합니다.
[1, 2, 3][1:] # 리스트 ✅ → [2, 3]
(1, 2, 3)[1:] # 튜플 ✅ → (2, 3)
"hello"[1:3] # 문자열 ✅ → "el"
# Java와 비교
"hello".substring(1, 3) // Java → "el"
"hello"[1:3] # Python → "el"
리스트를 간결하게 생성하는 Python의 핵심 문법입니다.
Java의 Stream API와 개념이 유사하지만, 훨씬 짧게 표현할 수 있습니다.
[표현식 for 변수 in 반복가능객체 if 조건]
읽는 순서대로 해석하면 이렇습니다.
"반복가능객체에서 변수를 하나씩 꺼내서, 조건을 만족하는 것만, 표현식으로 변환해 리스트로 만든다"
if 조건 은 생략 가능합니다.
numbers = [1, 2, 3, 4, 5]
# 조건 없이 - 모든 요소에 *2
[x * 2 for x in numbers]
# → [2, 4, 6, 8, 10]
# 조건 있이 - 짝수만 추출 후 *2
[x * 2 for x in numbers if x % 2 == 0]
# → [4, 8]
// Java
numbers.stream()
.filter(x -> x % 2 == 0)
.map(x -> x * 2)
.collect(Collectors.toList());
# Python - 한 줄로 끝
[x * 2 for x in numbers if x % 2 == 0]
2차원 리스트를 1차원으로 펼칠 때도 사용할 수 있습니다.
matrix = [[1, 2, 3], [4, 5, 6]]
# "matrix의 각 row에서 x를 꺼내 펼친다"
[x for row in matrix for x in row]
# → [1, 2, 3, 4, 5, 6]
Java의 HashMap에 해당하는 자료형입니다.
{key: value} 형태로 표기하며, key-value 쌍으로 데이터를 저장합니다.
person = {
"name": "Alice",
"age": 30
}
# 요소 추가 / 수정
person["email"] = "alice@example.com"
# 요소 삭제
del person["age"]
딕셔너리에서 값을 꺼내는 방법은 두 가지입니다.
person["name"] # "Alice"
person["email"] # 키가 없으면 KeyError 발생 💥
person.get("email") # 키가 없으면 None 반환 ✅
person.get("email", "없음") # 키가 없으면 기본값 반환 ✅
[]접근 vs.get()접근
키가 반드시 존재한다고 확신할 때 →[]
키가 없을 수도 있을 때 →.get()(안전)
Python의
None은 Java의null에 해당합니다.
| Java HashMap | Python dict | |
|---|---|---|
| 생성 | new HashMap<>() | {} |
| 값 접근 | map.get("key") | dict["key"] 또는 dict.get("key") |
| 키 없을 때 | null 반환 | dict["key"] → KeyError 발생 |
| 기본값 지정 | getOrDefault("key", "기본값") | dict.get("key", "기본값") |
Python 3.6부터 도입된 문자열 포맷팅 방법으로,
Java의 String.format() 보다 훨씬 직관적입니다.
문자열 앞에 f 를 붙이고, {} 안에 변수나 표현식을 넣으면 됩니다.
name = "Alice"
age = 30
# Java
String.format("이름: %s, 나이: %d", name, age) // "이름: Alice, 나이: 30"
# Python f-string
f"이름: {name}, 나이: {age}" # "이름: Alice, 나이: 30"
단순 변수 삽입뿐 아니라, 연산이나 메서드 호출도 바로 넣을 수 있습니다.
f"{2 + 3}" # "5"
f"{name.upper()}" # "ALICE"
f"{'짝수' if age % 2 == 0 else '홀수'}" # "짝수"
f"원주율: {3.14159:.2f}" # "원주율: 3.14" - 소수점 2자리
리스트를 순회할 때 인덱스와 요소를 함께 가져올 수 있게 해줍니다.
fruits = ["apple", "banana", "kiwi"]
# Java
<for (int i = 0; i < fruits.size(); i++) {
System.out.println(i + " " + fruits.get(i));
}
# Python - enumerate 없이
for i in range(len(fruits)):
print(i, fruits[i])
# Python - enumerate 사용 ✅
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 apple
# 1 banana
# 2 kiwi
enumerate 는 내부적으로 (index, 요소) 형태의 tuple 을 반환하는 iterator입니다.
for i, fruit in 은 이 tuple을 Unpacking 하는 것입니다.
enumerate(fruits)
# → (0, "apple"), (1, "banana"), (2, "kiwi") 를 하나씩 반환하는 iterator
# 즉, 아래와 동일
for item in enumerate(fruits):
i, fruit = item # Unpacking
print(i, fruit)
기본값은 0이지만, 시작 인덱스를 변경할 수 있습니다.
for i, fruit in enumerate(fruits, start=1):
print(i, fruit)
# 1 apple
# 2 banana
# 3 kiwi
여러 iterable을 같은 인덱스끼리 묶어서 tuple로 반환합니다.
두 리스트를 동시에 순회할 때 유용합니다.
fruits = ["apple", "banana", "kiwi"]
prices = [1000, 2000, 3000]
# Java - 인덱스로 직접 접근
for (int i = 0; i < fruits.size(); i++) {
System.out.println(fruits.get(i) + " " + prices.get(i));
}
# Python - zip 사용 ✅
for fruit, price in zip(fruits, prices):
print(fruit, price)
# apple 1000
# banana 2000
# kiwi 3000
zip 은 내부적으로 같은 인덱스의 요소를 tuple로 묶은 iterator입니다.
zip(fruits, prices)
# → ("apple", 1000), ("banana", 2000), ("kiwi", 3000) 을 하나씩 반환
# for fruit, price in 은 tuple을 Unpacking 하는 것
리스트 길이가 다르면 짧은 쪽에 맞춰서 끊깁니다.
a = [1, 2, 3, 4, 5]
b = [10, 20, 30]
for x, y in zip(a, b):
print(x, y)
# 1 10
# 2 20
# 3 30 ← b가 끝나면 중단
for i, (fruit, price) in enumerate(zip(fruits, prices)):
print(f"{i}번: {fruit} - {price}원")
# 0번: apple - 1000원
# 1번: banana - 2000원
# 2번: kiwi - 3000원
반복문이 break 없이 정상적으로 끝났을 때 else 블록이 실행됩니다.
break 로 탈출하면 else 는 실행되지 않습니다.
numbers = [1, 2, 3, 4, 5]
# break 없이 끝난 경우 → else 실행
for n in numbers:
print(n)
else:
print("반복 완료!") # 실행됨
# break로 탈출한 경우 → else 실행 안 됨
for n in numbers:
if n == 3:
break
else:
print("반복 완료!") # 실행 안 됨
예외처리의 try-else 와 같은 철학입니다.
| else 실행 O | else 실행 X | |
|---|---|---|
try-else | 예외 없이 정상 종료 | 예외 발생 |
for-else | break 없이 정상 종료 | break로 탈출 |
# Java - 별도 flag 변수 필요
boolean found = false;
for (int n : numbers) {
if (n == 3) { found = true; break; }
}
if (!found) System.out.println("못 찾았어요");
# Python - flag 변수 없이 깔끔하게
for n in numbers:
if n == 3:
break
else:
print("못 찾았어요") # break 없이 끝나면 실행
→ 2편에서 with, 함수, 클래스, 예외처리, import, Decorator, Generator 를 이어서 다룹니다.