클래스
클래스(Class)란?
객체를 만들기 위한 일종의 설계도.
어떠한 객체가 가져야 될 속성(데이터, 특징)과 행동(기능)을 미리 정한 일종의 규칙이다.
클래스는 메모리에 직접 사용되는 대상이 아닌 객체를 생성하기 위한 설계 정보만을 담고 있다. 때문에 클래스 자체로는 아무 동작을 하지 않는다.
객체와 인스턴스의 관계 정리
거의 같은 의미로 사용되고 혼용되며 큰 차이점을 보이지 않는다.
다만 정리하면
• 객체(Object): 클래스를 통해서 만들어진 실제 결과물 자체를 말할 때 사용
• 인스턴스(Instance): 어느 클래스에서 만들어졌는지를 강조할 때 사용
예시 문장:
• p1은 Person 클래스의 인스턴스이다.
• p1은 하나의 객체이다.
대략적 흐름
1. 클래스를 정의한다.
2. 클래스를 호출한다.
3. 호출한 결과로 인스턴스(객체)가 생성된다.
4. 생성된 인스턴스를 변수에 저장해 사용한다.
이 흐름이 가장 핵심적인 흐름이다.
클래스 정의와 기본 구조
클래스 정의
클래스는 class 키워드를 사용해 정의한다.
class 클래스이름:
속성(변수)
메소드(함수)
클래스 이름은 관례적으로 단어의 첫 글자를 대문자로 작성한다.
이는 코드 차원에서 “이 식별자는 클래스다”라는 의미를 명확히 하기 위한 규칙이며, 가독성과 유지보수성을 높이는 데 목적이 있다
클래스 자체는 실행 가능한 대상이 아니며, 객체를 생성하기 위한 설계 정보만을 포함한다.
생성자의 의미 (__init__)
(__init__) 메소드는 인스턴스가 생성될 때 자동으로 실행되는 함수이며 생성자라 부른다.
def __init__(self, name, age):
self.name = name
self.age = age
생성자의 역할은 다음과 같다.
• 인스턴스가 생성될 시 초기 상태를 설정한다.
• 인스턴스가 반드시 가져야 될 속성을 정의한다.
• 객체 생성과 동시에 필요한 준비 작접을 수행한다.
즉, 생성자는 이 객체는 생성될때 어떤 값을 가지고 시작할 것인가 를 정의한다.
self의 개념과 역할
• self는 현재 생성되거나 사용 중인 인스턴스 자신을 의미한다.
• 생성자 및 모든 인스턴스 메소드의 첫 번째 매개변수로 사용한다.
• self.변수명 형태로 선언된 변수는 인스턴스 변수가 된다.
self를 통해 각 인스턴스는 서로 다른 값을 독립적으로 유지 가능하다.
사용예시
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)
클래스를 호출할 경우 새로운 인스턴스가 생성된다.
설령 같은 클래스에서 만들어졌다 하여도 각 인스턴스는 서로 독립적인 상태를 유지한다.
p1 = Person("Alice", 25)
p2 = Person("Bob", 30)
사용 예시 실행 순서
| 1. Person 클래스가 호출된다 2. 새로운 인스턴스가 메모리에 생성된다. 3. __init__ 메소드가 자동 실행된다 4. 전달된 인자가 인스턴스 변수로 저장된다. 5 생성된 인스턴스는 변수에 할당되어 사용된다. |
이때 각 인스턴스는 서로 다른 메모리 공간을 가지며, 한 인스턴스의 상태 변화는 다른 인스턴스에 영향을 주지 않는다.
인스턴스 변수와 클래스 변수
인스턴스 변수
self.name
self.age
인스턴스 변수는 각 객체(인스턴스) 내부에 개별적으로 저장되는 데이터이다.
• 생성자(__init__)나 인스턴스 메서드 안에서 self.변수명 형태로 정의된다.
• 인스턴스마다 서로 다른 값을 가질 수 있다.
• 객체의 개별 상태(state) 를 표현하는 데 사용된다.
즉, “이 객체만 가지고 있는 정보”를 저장하는 용도이다.
객체마다 달라질수 있는 값에 사용해야 한다.
클래스 변수
class Car:
wheels = 4
클래스 변수는 클래스 내부에 정의되며, 해당 클래스로부터 만들어진 모든 인스턴스가 공유하는 데이터이다.
• 클래스 블록 내부에서 self 없이 정의된다.
• 모든 인스턴스가 같은 값을 참조한다.
• 공통 속성, 기준값, 상태 공유 목적에 사용된다.
예시에서 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()
핵심 특징
• 첫 번째 매개변수로 self를 받는다
• self는 메소드를 호출한 인스턴스 자신을 가리킨다
• 인스턴스 변수에 접근하고 수정할 수 있다
• 가장 일반적이고 기본적인 메소드 형태이다
즉, 인스턴스 메소드는 항상 “어떤 인스턴스에 대해 실행되는 함수” 라고 이해하면 된다.
클래스 메소드
개별 인스턴스가 아닌, 클래스 전체와 관련된 동작을 정의하는 메소드이다.
클래스 단위로 상태를 관리하며 모든 인스턴스가 공유하는 정보 처리한다.
즉, “이 클래스 전체에 대해 무엇을 할 것인가”를 표현한다.
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명이 만들어졌습니다."
핵심 특징
• @classmethod 데코레이터를 사용한다
• 첫 번째 매개변수로 cls를 받는다
• cls는 클래스 자신을 가리킨다
• 클래스 변수에 접근하거나 수정할 수 있다
정적 메소드
클래스와 논리적으로는 관련이 있지만, 인스턴스나 클래스의 상태에는 전혀 의존하지 않는 메소드이다.
어느 쪽에도 속하지 않는 함수, 그냥 “관련 있어서 묶어둔 함수”라 봐도 무방하다.
이 기능은 이 클래스와 묶여 있으면 이해는 쉬운데, 객체 상태와는 상관이 없다라는 경우에 사용한다.
class MathUtils:
@staticmethod
def add(a, b):
return a + b
result = MathUtils.add(3, 5)
print(result) # 8
핵심 특징
• @staticmethod 데코레이터를 사용한다
• 매개변수에 self, cls를 사용하지 않는다
• 일반 함수와 문법적으로 거의 동일하다
• 클래스 이름을 통해 호출한다
데코레이터의 의미 (@classmethod, staticmethod)
@classmethod
이 메소드가 인스턴스가 아니라 클래스 기준으로 호출되어야 함을 명확히 알려주는 표시이다.
이 데코레이터가 붙어 있기 때문에, self가 아닌 cls가 자동으로 전달되고 클래스 이름으로 직접 호출할 수 있다
언제 사용하는가
• 인스턴스 개수 관리
• 클래스 전체 상태 추적
• 생성자를 보조하는 대체 생성자 패턴
@staticmethod는
이 함수는 클래스 안에 있긴 하지만 어떤 객체나 클래스 상태도 자동으로 받지 않는다 라는 것을 명시한다.
표로 정리하기
| 구분 | 인스턴스 메소드 | 클래스 메소드 | 정적 메소드 |
| 기준 대상 | 인스턴스 | 클래스 | 없음 |
| 첫 매개변수 | self | cls | 없음 |
| 상태 접근 | 인스턴스 변수 | 클래스 변수 | 불가 |
| 주 용도 | 객체 행동 정의 | 클래스 상태 관리 | 독립 기능 |
접근 지정자와 캡슐화 (Encapsulation)
캡슐화의 개념
객체 내부의 데이터와 그 데이터를 다루는 로직을 하나로 묶고, 외부에서는 정해진 방법으로만 접근 가능하도록 제한하는 개념이다.
객체 내부 구현은 숨기고, 외부에선 필요한 기능만 사용 가능하게 해 데이터의 무결성과 안정성을 유지가 목적이다.
왜 사용하나?
• 외부에서 객체 내부 데이터를 직접 수정
• 잘못된 값이 들어와도 제어 불가능
• 객체 상태가 예기치 않게 깨침
위 사태를 방지하기 위함이라 할수 있다.
데이터를 함부로 건드리지 못하게 하고, 의도된 메서드를 통해서만 변경하도록 만드는 것이 중요하다.
접근 지정자 특징
파이썬 내부에서 접근 지정자를 언어 차원에서 강제하지 않지만
이름 규칙을 통해 접근 가능 범위를 표현한다.
이는 개발자 간의 약속, 문법적 보호 장치에 더 가깝다.
공개 맴버
self.owner
• 이름 앞에 언더스코어가 없는 변수
• 클래스 외부에서 자유롭게 접근 가능
보호 맴버
self._temp
• 이름 앞에 언더스코어 하나
• “외부에서 쓰지 말고 내부적으로 사용하라”는 암시한다.
비공개 맴버
self.__balance
• 이름 앞에 언더스코어 두 개
• 클래스 외부에서 직접 접근하기 어렵게 만든다
사용예시
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner # owner → 공개 멤버
self.__balance = 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 발생)
외부에서는 “잔액이 어떻게 저장되어 있는지”를 몰라도 정상적인 사용만 가능하도록 설계됨
클래스의 상속 (Inheritance)
상속의 개념
기존 클래스를 재사용해 새로운 클래스를 만들 수 있게 하는 기능이다.
기존 클래스의 속성과 메서드를 그대로 물려받아 사용할 수 있으며, 필요한 경우 기능을 추가하거나 기존 기능을 수정할 수 있다.
• 부모 클래스 (슈퍼 클래스): 상속해 주는 클래스
• 자식 클래스 (서브 클래스): 상속받는 클래스
사용예시
class Animal: # 부모 클래스
def __init__(self, name):
self.name = name
def speak(self):
print("동물이 소리를 냅니다.")
class Dog(Animal): # 자식 클래스: Animal 클래스를 상속
def speak(self):
print(f"{self.name}가 멍멍 짖습니다.")
# Animal 클래스를 상속해 name 속성을 그대로 사용하고 speak() 메서드는 자신에게 맞게 재정의
dog = Dog("멍멍이")
dog.speak() # "멍멍이가 멍멍 짖습니다."
위 예시에서 Dog 클래스는 Animal 클래스를 상속하여 name 속성과 speak() 메소드를 물려 받는다.
그리고 Dog 클래스에서 speak() 메서드를 재정의(오버라이딩)하여 특정한 동작을 구현 가능하다.
- 공통 기능의 상속
- 자식 클래스의 확장
다형성과 오버라이딩
다형성(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 인스턴스 -> "동물 소리"
'B.Review > 파이썬 라이브 세션' 카테고리의 다른 글
| [Python Study] 파이썬 4일차~문푸날 (0) | 2026.01.13 |
|---|---|
| [Python Study] 파이썬 3일차~문푸날 (0) | 2026.01.11 |
| [Python Study] 파이썬 2일차~문푸날 (0) | 2026.01.08 |
| [Python Study] 라이브세션 1회차~문푸날 (0) | 2026.01.06 |
