12_객체지향 프로그래밍, 어렵지 않아요! 핵심 개념 완전 정복 (클래스, 객체, 상속까지)
객체지향 프로그래밍, 어렵지 않아요! 핵심 개념 완전 정복 (클래스, 객체, 상속까지)
안녕하세요! 오늘은 파이썬의 객체지향 프로그래밍(OOP) 핵심 개념을 쉽고 체계적으로 정리해드립니다. 클래스, 객체, 상속 등 OOP의 기본부터 실전까지 한 번에 이해해보세요!
1. 객체(Object), 클래스(Class), 인스턴스(Instance)란?
기본 개념 이해하기
- 객체(Object): 고유의 **속성(데이터)**과 **기능(메서드)**을 가진, 식별 가능한 모든 것(예: 자동차, 학생, 계좌 등)
- 클래스(Class): 객체를 만들기 위한 설계도
- 붕어빵 틀(클래스) → 붕어빵(객체)
- 속성(필드)과 기능(메서드)로 구성
- 인스턴스(Instance): 클래스로부터 실제로 만들어진 객체
- 클래스와 인스턴스는 거의 같은 의미로 쓰이나, 인스턴스는 "실체"라는 느낌이 더 강함
class Car: # 클래스 정의
def drive(self):
print("부릉부릉~")
mycar = Car() # 인스턴스 생성
mycar.drive() # 객체의 메서드 호출
클래스의 구성 요소
클래스는 크게 두 가지 요소로 구성됩니다:
- 필드(Field): 클래스의 속성을 나타내는 변수
- 메서드(Method): 클래스 안에서 구현된 함수
class Student:
school = "파이썬고등학교" # 필드 (클래스 변수)
def __init__(self, name):
self.name = name # 필드 (인스턴스 변수)
def study(self): # 메서드
print(f"{self.name}이 공부하고 있습니다.")
self 매개변수의 중요성
메서드의 첫 번째 매개변수에 self를 사용하는 이유는 메서드 안에서 필드에 접근하기 위해서입니다.
class Calculator:
def __init__(self, value):
self.value = value
def add(self, num):
self.value += num # self를 통해 인스턴스 변수에 접근
return self.value
@staticmethod
def multiply(a, b): # 필드에 접근할 일이 없다면 self 생략 가능
return a * b
메서드 호출 방식: 인스턴스명.메서드명() 형식으로 사용합니다.
2. 생성자(Constructor)와 초기화
생성자의 개념
- 생성자: 인스턴스를 생성하면 무조건 호출되는 메서드
- 인스턴스를 생성하면서 필드값을 초기화시키는 함수
- 파이썬에서는 __init__() 이름을 가짐
기본 생성자 vs 매개변수가 있는 생성자
class Person:
# 기본 생성자 (매개변수가 self만 있음)
def __init__(self):
self.name = "이름없음"
self.age = 0
class Student:
# 매개변수가 있는 생성자
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def introduce(self):
print(f"안녕하세요! {self.name}입니다. {self.age}살이고 {self.grade}학년입니다.")
# 사용 예시
person1 = Person() # 기본 생성자 호출
student1 = Student("김철수", 16, 2) # 매개변수가 있는 생성자 호출
student1.introduce()
3. 인스턴스 변수와 클래스 변수
변수 타입의 차이점
- 인스턴스 변수: 인스턴스를 생성해야 비로소 사용할 수 있는 변수 (self.변수명)
- 클래스 변수: 클래스 안에 공간이 할당된 변수, 클래스 전체에서 공유
class Dog:
species = "개" # 클래스 변수 (모든 인스턴스가 공유)
def __init__(self, name, age):
self.name = name # 인스턴스 변수
self.age = age # 인스턴스 변수
# 클래스 변수 접근 방법
print(Dog.species) # 클래스명.클래스변수명
dog1 = Dog("멍멍이", 3)
dog2 = Dog("왈왈이", 5)
print(dog1.species) # 인스턴스.클래스변수명
print(dog2.species) # 같은 값 출력 (공유되는 변수)
# 각각 다른 인스턴스 변수
print(dog1.name) # 멍멍이
print(dog2.name) # 왈왈이
변수 구분하는 방법
인스턴스 변수와 클래스 변수가 이름이 동일할 때, 파이썬은 어떻게 구분할까요?
- self.변수명을 사용하면 인스턴스 변수
- 클래스명.변수명을 사용하면 클래스 변수
class Counter:
count = 0 # 클래스 변수
def __init__(self):
self.count = 1 # 인스턴스 변수 (같은 이름이지만 다른 변수!)
def show_count(self):
print(f"인스턴스 변수 count: {self.count}")
print(f"클래스 변수 count: {Counter.count}")
counter = Counter()
counter.show_count()
# 출력:
# 인스턴스 변수 count: 1
# 클래스 변수 count: 0
4. 상속(Inheritance)과 오버라이딩(Overriding)
상속의 개념
클래스의 상속은 기존 클래스에 있는 필드와 메서드를 그대로 물려받는 새로운 클래스를 만드는 것입니다.
- 상위클래스: 슈퍼클래스 또는 부모클래스
- 하위클래스: 서브클래스 또는 자식클래스
- 정의 방법: 서브클래스를 정의할 때 괄호 안에 슈퍼클래스의 이름을 넣음
class Animal: # 슈퍼클래스
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name}이 소리를 냅니다.")
def move(self):
print(f"{self.name}이 움직입니다.")
class Dog(Animal): # Animal을 상속받는 서브클래스
def __init__(self, name, breed):
super().__init__(name) # 부모 클래스의 생성자 호출
self.breed = breed
def speak(self): # 메서드 오버라이딩
print(f"{self.name}이 멍멍 짖습니다!")
def wag_tail(self): # 새로운 메서드 추가
print(f"{self.name}이 꼬리를 흔듭니다.")
# 사용 예시
my_dog = Dog("바둑이", "진돗개")
my_dog.speak() # 오버라이딩된 메서드 호출
my_dog.move() # 부모클래스에서 상속받은 메서드
my_dog.wag_tail() # 자식클래스의 새로운 메서드
메서드 오버라이딩
메서드 오버라이딩은 상위 클래스의 메서드를 서브 클래스에서 재정의하는 것입니다.
super() 함수
super() 함수는 서브클래스에서 메서드 오버라이딩을 할 때, 슈퍼클래스의 메서드나 속성을 사용해야 하는 경우에 사용합니다.
class Vehicle:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def start(self):
print(f"{self.brand} {self.model}이 시동을 걸었습니다.")
class Car(Vehicle):
def __init__(self, brand, model, fuel_type):
super().__init__(brand, model) # 부모 클래스 생성자 호출
self.fuel_type = fuel_type
def start(self):
super().start() # 부모 클래스의 start() 메서드 호출
print(f"연료: {self.fuel_type}")
my_car = Car("현대", "소나타", "가솔린")
my_car.start()
# 출력:
# 현대 소나타이 시동을 걸었습니다.
# 연료: 가솔린
5. 특별한 메서드(매직 메서드)
파이썬 클래스에는 특별한 용도로 사용되는 메서드들이 있습니다. 이들은 모두 __로 시작하고 끝납니다.
주요 특별한 메서드들
class Book:
def __init__(self, title, author, price):
self.title = title
self.author = author
self.price = price
def __del__(self): # 소멸자 (객체 삭제 시 호출)
print(f"'{self.title}' 책 객체가 삭제되었습니다.")
def __repr__(self): # print 등으로 객체 출력 시 호출
return f"Book('{self.title}', '{self.author}', {self.price}원)"
def __add__(self, other): # + 연산자 오버로딩
return self.price + other.price
def __lt__(self, other): # < 비교 연산자
return self.price < other.price
def __le__(self, other): # <= 비교 연산자
return self.price <= other.price
def __gt__(self, other): # > 비교 연산자
return self.price > other.price
def __ge__(self, other): # >= 비교 연산자
return self.price >= other.price
def __eq__(self, other): # == 비교 연산자
return self.price == other.price
def __ne__(self, other): # != 비교 연산자
return self.price != other.price
# 사용 예시
book1 = Book("파이썬 프로그래밍", "김파이", 25000)
book2 = Book("자바 프로그래밍", "이자바", 30000)
print(book1) # __repr__ 호출
print(book1 + book2) # __add__ 호출: 55000
print(book1 < book2) # __lt__ 호출: True
6. 추상 메서드(Abstract Method)
추상 메서드란?
서브클래스에서 메서드를 오버라이딩해서 사용하려면 슈퍼클래스에서 빈 껍질의 메서드만 만들어 놓고 내용은 pass로 채우면 됩니다.
추상 메서드는 슈퍼클래스에 본체가 없지만 서브 클래스에서는 반드시 오버라이딩해서 사용해야 합니다. 하지 않으면 NotImplementedError가 발생합니다.
class Shape:
def __init__(self, name):
self.name = name
def area(self): # 추상 메서드
raise NotImplementedError("서브클래스에서 반드시 구현해야 합니다!")
def perimeter(self): # 추상 메서드
pass # 또는 이렇게 pass로 처리
class Rectangle(Shape):
def __init__(self, width, height):
super().__init__("직사각형")
self.width = width
self.height = height
def area(self): # 추상 메서드 구현
return self.width * self.height
def perimeter(self): # 추상 메서드 구현
return 2 * (self.width + self.height)
class Circle(Shape):
def __init__(self, radius):
super().__init__("원")
self.radius = radius
def area(self): # 추상 메서드 구현
return 3.14159 * self.radius ** 2
def perimeter(self): # 추상 메서드 구현
return 2 * 3.14159 * self.radius
# 사용 예시
rect = Rectangle(10, 5)
circle = Circle(7)
print(f"{rect.name} 넓이: {rect.area()}")
print(f"{circle.name} 넓이: {circle.area()}")
7. 멀티스레드와 멀티프로세싱
스레드(Thread)
스레드는 프로그램 하나에서 여러 개를 동시에 처리할 수 있도록 제공하는 기능입니다. 동시에 스레드 여러 개를 작동하는 것을 멀티스레드라고 합니다.
import threading
import time
class Worker:
def __init__(self, name):
self.name = name
def work(self, duration):
print(f"{self.name} 작업 시작")
time.sleep(duration)
print(f"{self.name} 작업 완료")
# 멀티스레드 사용
worker1 = Worker("작업자1")
worker2 = Worker("작업자2")
# 스레드 생성: threading.Thread(target=메서드 또는 함수, args=(매개변수))
thread1 = threading.Thread(target=worker1.work, args=(3,))
thread2 = threading.Thread(target=worker2.work, args=(2,))
# 스레드 시작
thread1.start()
thread2.start()
# 스레드 완료 대기
thread1.join()
thread2.join()
print("모든 작업 완료!")
멀티프로세싱(Multiprocessing)
멀티프로세싱 기법은 동시에 CPU를 여러 개 사용합니다.
import multiprocessing
import time
class Calculator:
def heavy_calculation(self, n):
result = sum(i * i for i in range(n))
print(f"계산 완료: {result}")
return result
def calculate_process(n):
calc = Calculator()
calc.heavy_calculation(n)
if __name__ == "__main__":
# 멀티프로세싱 사용: multiprocessing.Process(target=메서드 또는 함수, args=(매개변수))
process1 = multiprocessing.Process(target=calculate_process, args=(1000000,))
process2 = multiprocessing.Process(target=calculate_process, args=(1000000,))
# 프로세스 시작
process1.start()
process2.start()
# 프로세스 완료 대기
process1.join()
process2.join()
print("모든 계산 완료!")
8. 실전 예시
프로그램 1: 학생 관리 시스템
class Student:
school_name = "파이썬 고등학교" # 클래스 변수
def __init__(self, name, student_id, grade):
self.name = name # 인스턴스 변수
self.student_id = student_id
self.grade = grade
self.subjects = []
def add_subject(self, subject):
self.subjects.append(subject)
def show_info(self):
print(f"학교: {Student.school_name}")
print(f"이름: {self.name}")
print(f"학번: {self.student_id}")
print(f"학년: {self.grade}")
print(f"수강과목: {', '.join(self.subjects)}")
class GraduateStudent(Student): # 상속
def __init__(self, name, student_id, grade, research_topic):
super().__init__(name, student_id, grade)
self.research_topic = research_topic
def show_info(self): # 오버라이딩
super().show_info()
print(f"연구주제: {self.research_topic}")
# 사용 예시
student1 = Student("김철수", "2021001", 2)
student1.add_subject("수학")
student1.add_subject("과학")
student1.show_info()
print("\n" + "="*30 + "\n")
grad_student = GraduateStudent("박박사", "2020001", 4, "AI 연구")
grad_student.show_info()
프로그램 2: 도형 그리기 시스템
import turtle
class Shape:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
self.turtle = turtle.Turtle()
self.turtle.speed(3)
def move_to_position(self):
self.turtle.penup()
self.turtle.goto(self.x, self.y)
self.turtle.pendown()
self.turtle.color(self.color)
def draw(self):
pass # 추상 메서드
class Rectangle(Shape):
def __init__(self, x, y, color, width, height):
super().__init__(x, y, color)
self.width = width
self.height = height
def draw(self):
self.move_to_position()
for _ in range(2):
self.turtle.forward(self.width)
self.turtle.right(90)
self.turtle.forward(self.height)
self.turtle.right(90)
class Circle(Shape):
def __init__(self, x, y, color, radius):
super().__init__(x, y, color)
self.radius = radius
def draw(self):
self.move_to_position()
self.turtle.circle(self.radius)
# 사용 예시 (주석 처리 - 실제 실행시에는 주석 해제)
# screen = turtle.Screen()
# screen.setup(800, 600)
# rect1 = Rectangle(-100, 100, "blue", 150, 100)
# rect2 = Rectangle(50, 50, "red", 100, 80)
# circle1 = Circle(-50, -100, "green", 60)
# rect1.draw()
# rect2.draw()
# circle1.draw()
# screen.exitonclick()
마무리
객체지향 프로그래밍의 핵심은 클래스와 객체의 설계에 있습니다. 오늘 배운 내용을 정리하면:
- 클래스와 객체: 설계도와 실제 인스턴스의 관계
- 필드와 메서드: 데이터와 기능의 캡슐화
- 생성자: 객체 초기화의 중요성
- 상속과 오버라이딩: 코드 재사용과 확장성
- 특별한 메서드: 파이썬다운 객체 설계
- 추상 메서드: 일관된 인터페이스 제공
- 멀티스레드/프로세싱: 동시 처리를 통한 성능 향상
이러한 개념들을 잘 익히면 더 체계적이고 확장성 높은 코드를 만들 수 있습니다. 실제 프로젝트에서는 이런 패턴들을 조합해서 복잡한 시스템을 구축하게 됩니다.
파이썬 객체지향 프로그래밍 시험 핵심 요약 🎯
📌 시험 출제 포인트 TOP 10
- 클래스와 인스턴스의 차이점
- self 매개변수의 역할과 사용법
- 생성자 __init__()의 역할
- 인스턴스 변수 vs 클래스 변수
- 상속 문법과 super() 함수
- 메서드 오버라이딩
- 특별한 메서드(매직 메서드)
- 추상 메서드의 개념
- 스레드와 프로세스 차이점
- 객체지향 용어 정리
🔑 핵심 개념 암기 카드
1. 기본 용어 정리
용어 | 정의 | 예시 |
클래스(Class) | 객체를 만들기 위한 설계도 | class Car: |
객체(Object) | 속성과 기능을 가진 실체 | 자동차, 학생, 계좌 |
인스턴스(Instance) | 클래스로부터 만들어진 실제 객체 | car1 = Car() |
필드(Field) | 클래스의 속성(변수) | self.name = "김철수" |
메서드(Method) | 클래스 안의 함수 | def drive(self): |
2. 변수 타입 구분
변수 타입 | 특징 | 접근 방법 | 예시 |
인스턴스 변수 | 각 객체마다 개별 존재 | self.변수명 | self.name = "철수" |
클래스 변수 | 모든 인스턴스가 공유 | 클래스명.변수명 | Student.school = "파이썬고" |
🚨 시험 포인트: 같은 이름의 변수가 있을 때
- self.count → 인스턴스 변수
- ClassName.count → 클래스 변수
📋 특별한 메서드(매직 메서드) 완전 정리
필수 암기 메서드
메서드 | 용도 | 호출 시점 | 예시 |
__init__(self) | 생성자 | 객체 생성 시 | obj = Class() |
__del__(self) | 소멸자 | 객체 삭제 시 | del obj |
__repr__(self) | 문자열 표현 | print(obj) 시 | print(book) |
__str__(self) | 사용자용 문자열 | str(obj) 시 | str(book) |
연산자 오버로딩 메서드
메서드 | 연산자 | 의미 | 예시 사용 |
__add__(self, other) | + | 덧셈 | obj1 + obj2 |
__sub__(self, other) | - | 뺄셈 | obj1 - obj2 |
__mul__(self, other) | * | 곱셈 | obj1 * obj2 |
__truediv__(self, other) | / | 나눗셈 | obj1 / obj2 |
비교 연산자 메서드
메서드 | 연산자 | 의미 | 예시 사용 |
__lt__(self, other) | < | 작다 | obj1 < obj2 |
__le__(self, other) | <= | 작거나 같다 | obj1 <= obj2 |
__gt__(self, other) | > | 크다 | obj1 > obj2 |
__ge__(self, other) | >= | 크거나 같다 | obj1 >= obj2 |
__eq__(self, other) | == | 같다 | obj1 == obj2 |
__ne__(self, other) | != | 다르다 | obj1 != obj2 |
🏗️ 상속 관련 핵심 정리
상속 문법
class 부모클래스:
pass
class 자식클래스(부모클래스): # 괄호 안에 부모클래스명
pass
상속 용어 정리
용어 | 다른 표현 | 의미 |
슈퍼클래스 | 부모클래스, 상위클래스 | 상속을 해주는 클래스 |
서브클래스 | 자식클래스, 하위클래스 | 상속을 받는 클래스 |
super() 함수 사용법
용도 | 문법 | 예시 |
부모 생성자 호출 | super().__init__() | 자식 클래스 생성자에서 |
부모 메서드 호출 | super().메서드명() | 오버라이딩에서 부모 기능 사용 |
🧵 멀티스레드 vs 멀티프로세싱
기본 개념 비교
구분 | 멀티스레드 | 멀티프로세싱 |
정의 | 하나 프로그램에서 여러 작업 동시 처리 | 여러 CPU를 동시에 사용 |
모듈 | threading | multiprocessing |
생성 문법 | threading.Thread() | multiprocessing.Process() |
매개변수 | target=함수, args=(인수,) | target=함수, args=(인수,) |
사용 문법 정리
# 멀티스레드
import threading
thread = threading.Thread(target=함수명, args=(매개변수,))
thread.start()
thread.join()
# 멀티프로세싱
import multiprocessing
process = multiprocessing.Process(target=함수명, args=(매개변수,))
process.start()
process.join()
📝 시험 출제 예상 문제 유형
1. 빈칸 채우기 (매우 출제 가능성 높음)
class Student:
school = "파이썬대학교" # ① 클래스 변수
def _______(self, name): # ② __init__
_______.name = name # ③ self
def study(self):
print(f"{______.name}이 공부합니다") # ④ self
class GradStudent(______): # ⑤ Student
def __init__(self, name, major):
______().__init__(name) # ⑥ super
self.major = major
2. 실행 결과 예측
class Counter:
count = 0
def __init__(self):
self.count = 1
Counter.count += 1
c1 = Counter()
c2 = Counter()
print(c1.count) # ① 1
print(Counter.count) # ② 2
3. 코드 작성 문제
"다음 조건을 만족하는 클래스를 작성하시오"
- Book 클래스
- 제목, 저자, 가격을 속성으로 가짐
- 두 책의 가격을 비교하는 메서드
- 책 정보를 출력하는 메서드
🎯 암기용 핵심 체크리스트
✅ 꼭 외워야 할 것들
- self의 역할: 메서드에서 인스턴스 변수에 접근하기 위해 필요
- 생성자: __init__(), 객체 생성 시 자동 호출
- 메서드 호출: 인스턴스명.메서드명() 형식
- 상속 문법: class 자식(부모):
- 오버라이딩: 부모 메서드를 자식에서 재정의
- 클래스 변수 접근: 클래스명.변수명 또는 인스턴스.변수명
- 추상 메서드: 내용이 pass이거나 NotImplementedError 발생
⚠️ 실수하기 쉬운 포인트
- self 빼먹기: 메서드 첫 번째 매개변수는 항상 self
- 괄호 실수: 상속할 때 class Child(Parent): 괄호 필수
- 들여쓰기: Python에서 매우 중요!
- 변수 구분: self.변수 vs 클래스명.변수
🔍 마지막 점검용 키워드
영어 | 한글 | 핵심 |
Class | 클래스 | 설계도 |
Object | 객체 | 실체 |
Instance | 인스턴스 | 실제 생성된 객체 |
Inheritance | 상속 | 부모 → 자식 |
Overriding | 오버라이딩 | 메서드 재정의 |
Constructor | 생성자 | __init__() |
Destructor | 소멸자 | __del__() |
Abstract Method | 추상 메서드 | pass 또는 NotImplementedError |
💡 시험 직전 마지막 체크
- self 매개변수 - 모든 인스턴스 메서드의 첫 번째 매개변수
- init() 생성자 - 객체 생성 시 자동 호출
- 상속 문법 - class Child(Parent):
- super() 함수 - 부모 클래스 접근
- 특별한 메서드 - __add__, __lt__ 등 연산자 오버로딩
- 스레드 vs 프로세스 - threading vs multiprocessing
🎓 시험 화이팅! 이 요약본만 완벽히 외우면 고득점 확실합니다!
궁금한 점은 댓글로 남겨주세요!
감사합니다 😊