Python에서는 함수와 dict만으로도 꽤 많은 문제를 풀 수 있습니다.
그래서 클래스를 배울 때는 문법보다 언제 class로 묶는 편이 더 자연스러운가, 그리고 self와 인스턴스 상태를 어떻게 읽어야 하는가를 먼저 잡는 편이 좋습니다.
숏컷 코드
class User:
def __init__(self, name: str) -> None:
self.name = name
self.login_count = 0
def greet(self) -> str:
return f"Hello, {self.name}"
def mark_login(self) -> None:
self.login_count += 1문법
기본형은 클래스 정의, 생성자 __init__, 인스턴스 메서드를 함께 보면 됩니다.
class User:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, {self.name}"class는 관련 있는 상태와 동작을 하나의 타입으로 묶고, __init__는 인스턴스 초기 상태를 만들며, 메서드는 그 상태에 붙는 동작을 뜻합니다.
클래스 선택
class가 정말 필요한가
함수와 딕셔너리만으로도 많은 문제를 풀 수 있지만, 어떤 데이터가 항상 함께 움직이고 그 데이터에 대한 동작도 고정돼 있다면 클래스로 묶는 편이 더 자연스럽습니다.
class BankAccount:
def __init__(self, owner: str, balance: int) -> None:
self.owner = owner
self.balance = balance
def deposit(self, amount: int) -> None:
self.balance += amount즉 클래스는 "기능 추가"보다 "관련 있는 것을 함께 관리"하는 구조입니다.
인스턴스 모델
self는 현재 인스턴스를 가리킨다
인스턴스 메서드의 첫 번째 인자 self는 지금 호출 중인 객체 자신입니다.
Python이 호출 시 자동으로 넣어 주기 때문에, user.greet()처럼 부를 수 있습니다.
class User:
def __init__(self, name: str) -> None:
self.name = name
def greet(self) -> str:
return f"Hello, {self.name}"
user = User("Mina")
print(user.greet())self.name처럼 쓰는 이유는 지역변수와 인스턴스 속성을 구분하고, 객체마다 독립적인 상태를 갖게 하기 위해서입니다.
인스턴스마다 상태가 따로 있어야 한다
클래스의 핵심 중 하나는 "객체마다 독립적인 상태"입니다. 같은 클래스로 여러 객체를 만들어도 각 인스턴스는 자기 상태를 따로 가집니다.
user_a = User("Mina")
user_b = User("Jin")이 감각이 잡히면 왜 self.attr가 필요한지도 자연스럽게 이어집니다.
구조 비교
데이터 묶음이 중심이면 dataclass나 dict도 비교한다
클래스가 항상 정답은 아닙니다.
동작보다 데이터 묶음이 핵심이라면 dataclass가 더 간단하고, 잠깐 쓰는 구조라면 dict가 더 나을 수 있습니다.
from dataclasses import dataclass
@dataclass
class Point:
x: int
y: int따라서 "행동을 가진 객체인가, 데이터 묶음인가"를 먼저 판단하는 편이 좋습니다.
주의할 점
클래스 속성과 인스턴스 속성을 헷갈리면 모든 객체가 같은 값을 공유하는 버그가 생길 수 있습니다.
# ❌ 변경 가능한 클래스 속성을 모든 인스턴스가 공유
class Team:
members = []
team_a = Team()
team_b = Team()
team_a.members.append("Mina")
print(team_b.members) # ['Mina']
# ✅ 인스턴스마다 별도 상태를 만든다
class Team:
def __init__(self) -> None:
self.members = []참고 링크
2 sources