클래스 = 객체(object)를 만들기 위한 설계도 또는 틀.
비유:
붕어빵 틀 = 클래스
붕어빵 = 객체 (인스턴스)
클래스는 속성과 동작을 정의한다.
객체(object/instance): 클래스를 바탕으로 메모리에 실제로 생성된 데이터.
어떤 규약이나 틀..프로그래밍에서 규약의 역할을 하는게 클래스.
(어떤 대상을 추상화하여 표현해서 나타내는 것)
규약을 통해 만들어낸 실제 형태 - 객체 (object)
클래스 없이 코딩을 하면,
# 학생 1
student1_name = "김철수"
student1_age = 20
student1_major = "컴퓨터공학"
# 학생 2
student2_name = "이영희"
student2_age = 21
student2_major = "경영학"
# 학생 3
student3_name = "박민수"
student3_age = 19
student3_major = "수학"
# 😱 학생이 100명이면...?
클래스 사용 시:
class Student:
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
# 객체 생성 (훨씬 간단!)
student1 = Student("김철수", 20, "컴퓨터공학")
student2 = Student("이영희", 21, "경영학")
student3 = Student("박민수", 19, "수학")
print(student1.name) # 김철수
print(student2.age) # 21
class Dog:
pass # 아무것도 없는 빈 클래스
# 객체 생성
my_dog = Dog()
class Dog:
# 생성자 (객체가 만들어질 때 자동 실행)
def __init__(self, name, age):
self.name = name # 속성
self.age = age # 속성
# 객체 생성
dog1 = Dog("멍멍이", 3)
dog2 = Dog("바둑이", 5)
print(dog1.name) # 멍멍이
print(dog2.age) # 5
Dog: 클래스
dog1, dog2: 객체 인스턴스 (실제 만들어진 것)
name, age: 속성 (객체가 가진 데이터)
init: 생성자 (초기화 함수)
self: 자기자신을 가리키는 키워드
== 나 자신을 가리키는 특별한 변수
class Dog:
def __init__(self, name):
self.name = name # self.name = 이 객체의 name
dog1 = Dog("멍멍이")
dog2 = Dog("바둑이")
# dog1.name → dog1의 name
# dog2.name → dog2의 name
비유:
# "내 이름은 ___입니다" 라고 할 때
# 철수가 말하면: "내(self) 이름은 철수입니다"
# 영희가 말하면: "내(self) 이름은 영희입니다"
규칙:
class Dog:
def bark(self):
print(f"{self.name}이 짖습니다!")
dog = Dog("멍멍이")
dog.bark() # self는 자동으로 dog를 가리킴
메서드 = 클래스 안에 정의된 함수 (객체가 할수 있는 동작)
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
# 메서드 1: 짖기
def bark(self):
print(f"{self.name}: 멍멍!")
# 메서드 2: 정보 출력
def info(self):
print(f"이름: {self.name}, 나이: {self.age}살")
# 메서드 3: 나이 먹기
def birthday(self):
self.age += 1
print(f"{self.name}이 {self.age}살이 되었습니다!")
# 사용
dog = Dog("멍멍이", 3)
dog.bark() # 멍멍이: 멍멍!
dog.info() # 이름: 멍멍이, 나이: 3살
dog.birthday() # 멍멍이가 4살이 되었습니다!
생성자 = 객체가 만들어질 때 자동으로 실행되는 특별한 메서드
class Car:
def __init__(self, brand, color):
print("자동차가 만들어졌습니다!")
self.brand = brand
self.color = color
car = Car("현대", "빨강")
# 출력: 자동차가 만들어졌습니다!
기본값 설정
class Car:
def __init__(self, brand, color="흰색"):
self.brand = brand
self.color = color
car1 = Car("현대") # 색상 기본값 사용
car2 = Car("기아", "검정") # 색상 직접 지정
print(car1.color) # 흰색
print(car2.color) # 검정
클래스변수: 모든 객체가 공유
class Dog:
species = "포유류" # 클래스 변수 (모든 개가 공유)
def __init__(self, name):
self.name = name # 인스턴스 변수
dog1 = Dog("멍멍이")
dog2 = Dog("바둑이")
print(dog1.species) # 포유류
print(dog2.species) # 포유류 (같음!)
print(Dog.species) # 포유류 (클래스로 직접 접근)
# 클래스 변수 변경
Dog.species = "동물"
print(dog1.species) # 동물 (모두 바뀜!)
비유:
인스턴스 변수: 각 객체마다 다름
class Dog:
def __init__(self, name):
self.name = name # 인스턴스 변수
dog1 = Dog("멍멍이")
dog2 = Dog("바둑이")
print(dog1.name) # 멍멍이
print(dog2.name) # 바둑이 (다름!)
캡슐화 = 외부에서 직접 접근하지 못하게 숨기기
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.__balance = balance # __(언더스코어 2개) = private
def deposit(self, amount):
self.__balance += amount
def get_balance(self): # Getter
return self.__balance
def set_balance(self, balance): # Setter
if balance >= 0:
self.__balance = balance
account = BankAccount("철수", 10000)
# print(account.__balance) # 에러! 직접 접근 불가
print(account.get_balance()) # 10000 (메서드로만 접근)
왜 숨길까?
잘못된 값이 들어가는 것 방지
데이터 보호
내부 구현을 숨겨서 변경에 유연
상속 = 부모 클래스의 속성과 메서드를 물려받기
# 부모 클래스
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print("동물이 소리를 냅니다")
# 자식 클래스
class Dog(Animal): # Animal을 상속
def speak(self): # 메서드 오버라이딩 (재정의)
print(f"{self.name}: 멍멍!")
class Cat(Animal):
def speak(self):
print(f"{self.name}: 야옹~")
# 사용
dog = Dog("멍멍이")
cat = Cat("나비")
dog.speak() # 멍멍이: 멍멍!
cat.speak() # 나비: 야옹~
부모 메서드 호출 (super)
class Animal:
def __init__(self, name):
self.name = name
print(f"{name}이(가) 태어났습니다!")
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # 부모의 __init__ 호출
self.breed = breed
print(f"견종: {breed}")
dog = Dog("멍멍이", "진돗개")
# 출력:
# 멍멍이이(가) 태어났습니다!
# 견종: 진돗개
특별메서드=''로 시작하고 끝나는 특별한 기능을 가진 메서드
str__ (문자열 표현)
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"강아지(이름: {self.name}, 나이: {self.age}살)"
dog = Dog("멍멍이", 3)
print(dog) # 강아지(이름: 멍멍이, 나이: 3살)
len(길이)
class Playlist:
def __init__(self):
self.songs = []
def add(self, song):
self.songs.append(song)
def __len__(self):
return len(self.songs)
playlist = Playlist()
playlist.add("노래1")
playlist.add("노래2")
print(len(playlist)) # 2
add(덧셈)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2 # __add__ 호출
print(p3) # (4, 6)
# 클래스 = 설계도
class Dog:
# 클래스 변수 (모두 공유)
species = "포유류"
# 생성자 (초기화)
def __init__(self, name, age):
self.name = name # 인스턴스 변수
self.age = age
# 메서드 (기능)
def bark(self):
return f"{self.name}: 멍멍!"
# 특별 메서드
def __str__(self):
return f"Dog({self.name}, {self.age}살)"
# 객체 = 실제 만들어진 것
dog1 = Dog("멍멍이", 3)
dog2 = Dog("바둑이", 5)
다형성 = 하나의 인터페이스로 여러 형태의 구현을 다루는 것
예시
class Dog:
def 소리내(self):
print("멍멍!")
class Cat:
def 소리내(self):
print("야옹~")
class Cow:
def 소리내(self):
print("음메~")
# 같은 명령어 "소리내()"
강아지 = Dog()
고양이 = Cat()
소 = Cow()
강아지.소리내() # 멍멍!
고양이.소리내() # 야옹~
소.소리내() # 음메~
명령어는 똑같이 .소리내()
하지만 누구한테 시키느냐에 따라 결과 달라짐
eg)상속 없이도 작동
# 상속 관계 전혀 없음!
class 자동차:
def 출발(self):
print("🚗 부릉부릉 출발!")
class 비행기:
def 출발(self):
print("✈️ 이륙합니다!")
class 배:
def 출발(self):
print("⛵ 닻을 올립니다!")
# 모두 '출발()' 메서드만 있으면 작동
탈것들 = [자동차(), 비행기(), 배()]
for 탈것 in 탈것들:
탈것.출발() # 다형성!
# 출력:
# 🚗 부릉부릉 출발!
# ✈️ 이륙합니다!
# ⛵ 닻을 올립니다!
-> 자동차, 비행기, 배는 서로 관계 없음
-> 하지만 모두 출발() 메서드가 있으니까 같은 방식으로 처리가능.
파이썬에서는 다형성을 적용하기가 쉬움
즉, 타입을 미리 정하지 않아서 더 자유롭다.
실시간 결정
실행할 때 알아서 판단
연산자도 다형성
1 + 2 = 3 (숫자 더하기)
"a" + "b" = "ab" (문자 연결)
같은 + 인데 다르게 동작!
TV 리모컨 전원 버튼 → TV 켜짐
에어컨 리모컨 전원 버튼 → 에어컨 켜짐
선풍기 리모컨 전원 버튼 → 선풍기 켜짐
같은 "전원 버튼"인데 기기마다 다르게 동작!
강아지한테 "가져와!" → 공 물어옴
고양이한테 "가져와!" → 무시함
사람한테 "가져와!" → 손으로 가져옴
같은 명령인데 누구한테 하느냐에 따라 다름!
다형성 = 똑같은 이름, 다른 동작
# 핵심 코드
animals = [Dog(), Cat(), Cow()]
for animal in animals:
animal.speak() # 같은 speak()인데...
# 결과:
# 멍멍! ← Dog의 speak()
# 야옹~ ← Cat의 speak()
# 음메~ ← Cow의 speak()