알고리즘 Cheat Sheet 시리즈는 코딩 테스트를 풀다가 "이거 자바에선 뭐였지?", "파이썬은 어떻게 했더라?" 싶을 때 바로 펼쳐 보려고 만든 개인 참고용 정리입니다.
Java와 Python을 나란히 놓고, 문법 차이 때문에 실수하기 쉬운 부분만 짧게 정리합니다.

이번 주제는 클래스와 static입니다.
자바로 코테를 풀다 보면 static을 일단 붙이고 보자는 식으로 쓰게 되는데, 왜 붙여야 하는지와 파이썬에서는 무엇에 해당하는지를 정리해 봅시다.
| 항목 | 자바 | 파이썬 |
|---|---|---|
| 생성자 | 클래스 이름과 같은 메서드 | __init__(self, ...) |
| 자기 자신 참조 | this (생략 가능) | self (생략 불가) |
| 객체 생성 | new Point(1, 2) | Point(1, 2) |
| 필드 선언 | 클래스 본문에 타입과 함께 | __init__ 안에서 self.x = ... |
| 메서드 첫 번째 매개변수 | 없음 | self를 직접 적는다 |
| 접근 제어 | private, public 등 | 없음 (_이름은 관례일 뿐) |
class Point {
int x, y; // 필드 선언
Point(int x, int y) { // 생성자
this.x = x;
this.y = y;
}
int sum() { // 인스턴스 메서드
return x + y; // this.x에서 this 생략 가능
}
}
Point p = new Point(1, 2);
p.sum(); // 3
class Point:
def __init__(self, x, y): # 생성자
self.x = x # 여기서 필드가 만들어진다
self.y = y
def sum(self): # 인스턴스 메서드
return self.x + self.y # self 생략 불가
p = Point(1, 2)
p.sum() # 3
코테에서 좌표나 노드처럼 값 몇 개를 묶기만 할 때는 자바는
int[]나 클래스, 파이썬은 튜플(x, y)이 가장 간단하다.
| 구분 | 인스턴스 멤버 | static 멤버 |
|---|---|---|
| 소속 | 객체마다 따로 | 클래스에 하나 (모든 객체가 공유) |
| 사용 조건 | 객체를 만들어야 쓸 수 있다 | 객체 없이 쓸 수 있다 |
| 호출 | p.sum() | Math.max(a, b) |
| 개념 | 자바 | 파이썬 |
|---|---|---|
| 공유 변수 | static int count; | 클래스 본문에 count = 0 (클래스 변수) |
| 객체 없이 부르는 메서드 | static int add(int a, int b) | @staticmethod |
| 클래스 자체를 받는 메서드 | - | @classmethod (cls) |
| 상수 | static final int MOD = 1_000_000_007; | MOD = 10**9 + 7 (대문자는 관례) |
| 접근 | 클래스이름.count | 클래스이름.count |
class Counter {
static int count = 0; // 모든 객체가 공유
int id; // 객체마다 따로
Counter() {
count++;
id = count;
}
static int total() { // 객체 없이 호출 가능
return count;
}
}
new Counter(); new Counter();
Counter.total(); // 2
class Counter:
count = 0 # 클래스 변수 (모든 객체가 공유)
def __init__(self):
Counter.count += 1 # 클래스 이름으로 접근
self.id = Counter.count # 인스턴스 변수 (객체마다 따로)
@staticmethod
def total(): # self 없음, 객체 없이 호출 가능
return Counter.count
Counter(); Counter()
Counter.total() # 2
main이 static이기 때문!자바 프로그램은 객체를 만들기 전에 main부터 실행된다. 그래서 main은 static이고, static 메서드 안에서는 static 멤버만 바로 쓸 수 있다.
public class Main {
int n; // 인스턴스 변수
void dfs(int x) { } // 인스턴스 메서드
public static void main(String[] args) {
n = 5; // ❌ non-static variable n cannot be referenced from a static context
dfs(0); // ❌ non-static method dfs(int) cannot be referenced from a static context
}
}
해결 방법은 두 가지다.
// 방법 1: 전부 static으로 (백준 스타일, 가장 흔함)
static int n;
static void dfs(int x) { }
// 방법 2: 객체를 만들어서 호출
Main m = new Main();
m.dfs(0);
| 플랫폼 | 시작점 | static 필요 여부 |
|---|---|---|
| 백준 | public static void main | 보조 메서드와 공유 변수에 static 필요 |
| 프로그래머스 | class Solution의 solution() (인스턴스 메서드) | 필요 없음 |
재귀 함수 여러 번의 호출이 같은 배열과 답을 공유해야 할 때, 자바는 static 필드, 파이썬은 전역 변수를 쓴다.
public class Main {
static int n;
static boolean[] visited;
static List<List<Integer>> graph = new ArrayList<>();
static int answer = 0;
static void dfs(int cur) {
visited[cur] = true;
answer++;
for (int next : graph.get(cur)) {
if (!visited[next]) dfs(next);
}
}
}
import sys
sys.setrecursionlimit(10**6) # 파이썬 재귀 깊이 제한(기본 1000) 늘리기, 분할정복 시 필수다...
n = 5
visited = [False] * (n + 1)
graph = [[] for _ in range(n + 1)]
answer = 0
def dfs(cur):
global answer # 전역 변수에 "대입"하려면 global 선언
visited[cur] = True # 리스트 원소 수정은 global 없이 가능
answer += 1
for nxt in graph[cur]:
if not visited[nxt]:
dfs(nxt)
global vs nonlocal| 상황 | 필요한 선언 |
|---|---|
| 전역 변수 읽기 | 없음 |
전역 리스트 · 딕셔너리의 내용 수정 (visited[i] = True, d[k] = v) | 없음 |
전역 변수에 새 값 대입 (answer += 1, answer = 0) | global answer |
| 함수 안의 함수에서 바깥 함수 변수에 대입 | nonlocal answer |
def solution(n):
answer = 0
def dfs(x):
nonlocal answer # solution의 answer를 바꾸겠다는 뜻
answer += 1
dfs(0)
return answer
this와 인스턴스 멤버를 쓸 수 없다. 객체가 없을 수도 있기 때문이다.solution() 시작 부분에서 answer = 0;처럼 다시 초기화한다.static final 상수는 대문자로! static final int MOD = 1_000_000_007;self를 빼먹으면 에러가 난다...
class A:
def hello(): # self 누락
print("hi")
A().hello() # TypeError: A.hello() takes 0 positional arguments but 1 was given
self.count += 1은 클래스 변수를 바꾸지 않는다. 그 객체에 새 인스턴스 변수를 만들 뿐이다. 클래스 변수는 클래스이름.count += 1로 바꾼다.
class Counter:
count = 0
def inc(self):
self.count += 1 # 인스턴스 변수 count가 새로 생긴다
a = Counter(); a.inc()
print(a.count, Counter.count) # 1 0
클래스 변수에 리스트를 두면 모든 객체가 공유한다. 객체마다 따로 가져야 하면 __init__ 안에서 만든다.
class Bag:
items = [] # ❌ 모든 Bag이 같은 리스트를 쓴다
def __init__(self):
self.items = [] # ⭕ 객체마다 새 리스트
global 없이 대입하면 지역 변수가 새로 생긴다. answer += 1은 UnboundLocalError가 난다.
@staticmethodmain이 static이라서 보조 메서드와 공유 변수도 static, 프로그래머스 solution()은 인스턴스 메서드라 필요 없다.self를 적고, 필드는 항상 self.을 붙인다.global (함수 안의 함수는 nonlocal)클래스이름.변수로 바꾼다. self.변수 += 1은 다른 변수를 만든다.sys.setrecursionlimit을 잊지 말자.