클래스
클래스(Class)란?
객체를 만들기 위한 설계도라 할수 있다.
어떤 객체가 가져야 할 속성(데이터, 특징), 행동(기능)을 미리 정해둔 틀이라 이해해도 된다.
중요한 점은
클래스 자체는 실제 사물이 아닌 사물을 만들기 위한 일종의 규칙이라는 점이다.
즉, 클래스는 아직 만들어지지 않은 상태이며, 실제로 사용 가능한 대상은 클래스가 아닌 '객체'이다.
객체(Object)와 인스턴스(Instance)
거의 같은 의미로 혼용되어 사용되지만 정리하면
객체(Object)
클래스를 통해서 만들어진 실제 결과물
인스턴스(Instance)
특정 클래스로부터 생성된 객체를 그 클래스의 인스턴스라 부른다.
인스턴스랑 객체는 혼용되어 쓰이기도 한다.
대략적인 흐름
1. 클래스를 정의한다.
2. 클래스를 호출한다.
3. 호출한 결과로 인스턴스(객체)가 생성된다.
이 흐름이 가장 핵심적인 흐름이다.
클래스 정의와 구조
클래스의 정의
class 클래스이름:
속성(변수)
메서드(함수)
클래스 이름은 관례적으로 단어의 첫 글자를 대문자로 작성한다.
이는 “이 이름은 클래스다”라는 의미를 코드 차원에서 구분하기 위함이다.
생성자(__init__)의 의미
def __init__(self, name, age):
self.name = name
self.age = age
__init__ 메소드는 인스턴스가 생성될 때 자동으로 실행되는 함수이며 생성자라 부른다.
중요 포인트
인스턴스가 만들어질 때 해당 인스턴스가 가져야 할 초기 상태(속성 값)를 설정하는 역할
→ 생성자는 이 객체는 생성될때 어떤 값을 가지고 시작할 것인가 를 정의한다.
사용의 예시
class Person:
def __init__(self, name, age): # 생성자
self.name = name # 인스턴스 변수
self.age = age # 인스턴스 변수
def introduce(self):
print(f"안녕하세요, 제 이름은 {self.name}이고, 나이는 {self.age}살입니다.")
객체의 생성과 사용
p1 = Person("Alice", 25)
p2 = Person("Bob", 30)
실행 순서
| 1. Person 클래스가 호출된다 2. 새로운 인스턴스가 생성된다 3. __init__ 메서드가 자동 실행된다 4. 각 인스턴스는 서로 다른 메모리 공간을 가진다 |
같은 클래스에서 만들어졌더라도 값이 다르기에 각 인스턴스는 서로 독립적인 상태를 유지한다.
인스턴스 변수와 클래스 변수
인스턴스 변수
각 객체마다 따로 가지는 데이터이다.
self.name
self.age
• self.변수명 형태로 정의
• 인스턴스마다 값이 다를 수 있음
• 객체의 개별 상태를 표현
클래스 변수
모든 인스턴스가 공유하는 데이터이다.
class Car:
wheels = 4
이때, wheels는
“모든 자동차는 바퀴가 4개다”라는 공통 규칙을 표현한다.
메소드의 종류와 역할
클래스 안에 정의된 함수로 무엇을 기준으로 작동하느냐에 따라 역할이 나뉜다
인스턴스 메소드
각 객체(인스턴스)가 가진 데이터(인스턴스 변수)를 다루기 위한 메소드(함수)이다.
각 인스턴스마다 다른 값에 대해 동작하며 객체의 '행동'을 정의한다.
인스턴스를 기준으로 작동하는 함수로, 객체의 상태를 읽거나 변경하는 역할을 한다.
즉 “이 객체가 자기 자신에 대해 무엇을 할 수 있는가”를 표현한다.
class Person:
def __init__(self, name):
self.name = name
def say_hello(self): #인스턴스 메서드
print(f"Hello, my name is {self.name}")
person1 = Person("alice")
person1.say_hello()
이 형태는 “이 메소드는 반드시 어떤 인스턴스를 기준으로 실행된다”는 의미를 가진다.
클래스 메소드
개별 인스턴스가 아닌, 클래스 전체와 관련된 동작을 정의하는 메소드이다.
클래스 단위로 상태를 관리하며 모든 인스턴스가 공유하는 정보 처리한다.
클래스를 기준으로 작동하는 함수이다.
즉, “이 클래스 전체에 대해 무엇을 할 것인가”를 표현한다.
class Person:
count = 0
def __init__(self, name):
self.name = name
Person.count += 1
@classmethod
def how_many(cls):
print(f"지금까지 {cls.count}명이 만들어졌습니다.")
p1 = Person("Alice")
p2 = Person("Bob")
Person.how_many() # "지금까지 2명이 만들어졌습니다."
구조 파악
• 첫 번째 매개변수로 cls를 받는다
• cls는 클래스 자신을 가리킨다
• 클래스 변수에 접근 가능
• @classmethod 데코레이터를 사용
정적 메소드
클래스와 논리적으로는 관련이 있지만, 인스턴스나 클래스의 상태에는 전혀 의존하지 않는 메소드이다.
어느 쪽에도 속하지 않는 함수, 그냥 “관련 있어서 묶어둔 함수”라 봐도 무방하다.
즉, “이 기능은 이 클래스와 묶여 있으면 이해는 쉬운데, 객체 상태와는 상관이 없다”라는 경우에 사용한다.
class MathUtils:
@staticmethod
def add(a, b):
return a + b
result = MathUtils.add(3, 5)
print(result) # 8
구조 파악
• 매개변수에 self, cls 없음
• @staticmethod 데코레이터 사용
• 일반 함수와 문법적으로 거의 동일
표로 정리하기
| 구분 | 인스턴스 메소드 | 클래스 메소드 | 정적 메소드 |
| 기준 대상 | 인스턴스 | 클래스 | 없음 |
| 첫 매개변수 | self | cls | 없음 |
| 상태 접근 | 인스턴스 변수 | 클래스 변수 | 불가 |
| 주 용도 | 객체 행동 정의 | 클래스 상태 관리 | 독립 기능 |
클래스가 필요한 이유
클래스를 사용하면
1. 데이터와 기능을 하나로 묶을 수 있다
2. 코드 구조가 명확해진다
3. 재사용성과 확장성이 높아진다
4. 데이터 분석, 시뮬레이션, 모델링에 매우 적합하다
클래스 심화 (복습때 더 자세하게 다루기)
접근 지정자와 캡슐화
파이썬은 언어 차원에서 public, private 접근 제어자를 명시적으로 제공하지 않지만 관례적으로 변수나 메서드 앞에 언더스코어(_)를 붙여 내부적으로 사용함을 암시한다.
• _변수명: 해당 변수는 내부적 용도로 사용되는 것을 암시 (개발자간 약속)
• __변수명: 외부에서 접근하기 어렵게 강제한다. 즉, 클래스에 속한 메서드들만 이 변수에 접근할 수 있다.
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.__balance = balance # 이 변수는 직접 접근하기 어렵게 함.
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if self.__balance >= amount:
self.__balance -= amount
else:
print("잔고 부족")
def get_balance(self):
return self.__balance
acc = BankAccount("Alice", 1000)
print(acc.get_balance()) # 1000
acc.deposit(500)
print(acc.get_balance()) # 1500
acc.withdraw(2000) # "잔고 부족"
print(acc.get_balance()) # 1500
# acc.__balance 는 직접 접근 불가능 (AttributeError 발생)
이와 같이 캡슐화를 통해 내부 데이터는 메서드로만 접근 가능하게 하여 데이터 무결성을 보장한다.
상속
기존 클래스를 재사용해 새로운 클래스를 만들 수 있게 하는 기능
상속을 통해 기존 클래스(부모 클래스 또는 슈퍼 클래스)의 변수와 메소드를 자식클래스(서브 클래스)에서 물려 받을수 있다.
필요할경우 물려받은것을 확장하거나 수정할수도 있다.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print("동물이 소리를 냅니다.")
class Dog(Animal): # Animal 클래스를 상속
def speak(self):
print(f"{self.name}가 멍멍 짖습니다.")
dog = Dog("멍멍이")
dog.speak() # "멍멍이가 멍멍 짖습니다."
위 예시에서 Dog 클래스는 Animal 클래스를 상속하여 name 속성과 speak() 메소드를 물려 받는다.
그리고 Dog 클래스에서 speak() 메서드를 재정의(오버라이딩)하여 특정한 동작을 구현 가능하다.
다형성(Polymorphism)과 오버라이딩(Overriding)
다형성(Polymorphism)
같은 이름의 메서드가 서로 다른 객체에서 서로 다른 방식으로 동작하는 성질을 의미한다.
[호출 방식은 동일하지만 실제 실행되는 동작은 객체의 타입(클래스)에 따라 달라진다] 란 특징을 지닌다.
즉, 같은 메시지를 보내면, 객체에 따라 다른 행동을 한다.
오버라이딩(Overriding)
부모 클래스에 정의된 메소드를 자식 클래스에서 같은 이름으로 다시 정의하는 것이다.
부모 쿨래스의 메소드와 자식 클래스의 메소드는...
메소드의 이름이 같아야 하고, 매개변수 구조가 같아야 한다.
이후 자식 클래스의 메소드가 부모 클래스의 메소드를 덮어쓴다
즉, 자식 클래스가 부모의 행동을 자기 방식으로 바꾼다
class Animal: # 부모 클래스
def speak(self): # 행동 지정
print("동물 소리")
class Cat(Animal): # 자식 클래스
def speak(self): # speak()를 오버라이딩: 고양이 울음소리를 냄
print("야옹")
class Dog(Animal): # 자식 클래스
def speak(self): # speak()를 오버라이딩: 개의 울음소리를 냄
print("멍멍")
animals = [Cat(), Dog(), Animal()] # 모두 Animal 타입으로 취급 가능하나 실제 객체는 각각 다름
for a in animals:
a.speak()
# Cat 인스턴스 -> "야옹"
# Dog 인스턴스 -> "멍멍"
# Animal 인스턴스 -> "동물 소리"
클래스 메소드, 인스턴스 메소드 햇갈리니 복습할때 중점적으로 공부하기
'A.Today I Learne > 파이썬' 카테고리의 다른 글
| [TIL] 파이썬 4일차 (0) | 2026.01.12 |
|---|---|
| [TIL] 파이썬 3일차 (1) | 2026.01.09 |
| [TIL] 파이썬 2일차 (0) | 2026.01.07 |
| [TIL] 파이썬 1일차 (0) | 2026.01.05 |
