클래스는 새로운 타입을 정의하는 '붕어빵 틀'과 같습니다. 이 틀을 통해 만들어진 실체를 '객체' 또는 '인스턴스'라고 부릅니다.
class Cookie:
pass
# 인스턴스 생성
a = Cookie()
print(type(a)) # <class '__main__.Cookie'>
객체변수앞에서 말한 속성값과 같은 뜻입니다. 속성값이라고 불리고, 멤버 변수 혹은 필드라고 불립닏다.
__init__객체가 생성될 때 자동으로 호출되며, 주로 속성을 초기화하는 역할을 합니다.
메소드의 첫 번째 매개변수는 항상 self여야 합니다. 이는 호출된 '객체 자신'을 가리킵니다.
class Rectangle: #클래스 정의
def __init__(self, width=1, height=1): #객체가 생성되면 자동 호출
print(f"Rectangle({width}, {height}) 생성")
self.width = width #객체 변수 생성
self.height = height #객체 변수 생성
#메소드(함수) 정의
def get_area(self):
return self.width * self.height
def set_size(self, w, h):
self.width = w
self.height = h
#인스턴스 생성 및 자동 호출
r1 = Rectangle(30, 20)
#매개변수 없이 호출(기본값)
r2 = Rectangle()
#메소드 호출 및 결과 출력
print(r1.get_area()) # 600
print(r2.get_area()) # 1
#생성 후 객체 값 수정
r2.set_size(10, 50)
#수정 결과 출력
print(r2.get_area()) # 500
self.변수명. 각 객체마다 독립적인 값을 가집니다.클래스명.변수명으로 접근합니다. class Account:
num_accounts = 0 # 클래스 변수 (전체 계좌 수)
def __init__(self, name):
self.name = name # 인스턴스 변수
Account.num_accounts += 1
a1 = Account("철수")
# 1. '철수'라는 이름표를 가진 객체 생성
# 2. 공용 게시판(Account.num_accounts)의 숫자가 0에서 1이 됨
a2 = Account("영희")
# 1. '영희'라는 이름표를 가진 객체 생성
# 2. 공용 게시판(Account.num_accounts)의 숫자가 1에서 2가 됨
| 구분 | 인스턴스 변수 (self.name) | 클래스 변수 (Account.num_accounts) |
|---|---|---|
| 소유주 | 개별 객체 (인스턴스) | 클래스 전체 (모든 객체 공용) |
| 생성 시점 | 객체가 생성될 때마다 매번 | 클래스가 정의될 때 딱 한 번 |
| 접근 방법 | 객체명.변수명 | 클래스명.변수명 (권장) |
| 용도 | 객체의 고유한 특징 (이름, 잔액 등) | 모든 객체가 공유하는 정보 (전체 개수, 고정 이율 등) |
# '매 직원(PartTimer)'에 공통적으로 적용되는 자료
# - 시급
# - 전체 직원수
# 각 직원별 객체 생성시 직원별로 '별칭'과 '근무지' '급여총액' 초기화 (속성)
# '근무지' 생략시 '113동' 으로 지정
# 직원별로 '급여총액' 0으로 초기화
# 직원의 급여 계산하기(동작)
# '몇시간 근무', '+상여금' 에 따른 직원급여 계산
# '상여금' 은 지정안하면 0 으로 처리
# 예]
# park = PartTimer('라이언') // park 은 ‘라이언’ 이라는 닉네임의 직원으로 등록
# park 이 4시간 일한 급여 총액은? → 34400
# park 이 2시간 일한 급여 총액은? → 17200
# park 이 2시간 일한 급여 + 상여급 2000 총액은? → 19200
class PartTimer:
# 클래스변수
hour_rate = 10320 # 시급
total_part_timers = 0 # 전체 직원수
# 생성자 (nickname, workplace)
# 인스턴스 변수들 선언 (nickname, workplace, total_wage)
def __init__(self, nickname, workplace = "113동"):
PartTimer.total_part_timers += 1
self.nickname = nickname
self.workplace = workplace
self.total_wage = 0
# 급여계산
def calculate_wage(self, hours, bonus=0):
self.total_wage = PartTimer.hour_rate * hours + bonus
return self.total_wage
#실행하기
park = PartTimer('라이언')
lee = PartTimer('네오', '127-1동')
park.total_wage # 급여총액 0
lee.total_wage # 0
park.calculate_wage(4) # 시급 x 4
lee.calculate_wage(3, 15000) # 시급 x 3 + 보너스 15000
PartTimer.total_part_timers # 2 명
기존 클래스(부모)의 기능을 그대로 물려받아 새로운 클래스(자식)를 만드는 것입니다.
코드 재사용성이 높아집니다.
기존의 만들어진 클래스를 상속받아 새로운 클래스 정의 가능합니다.
상속받아 만들어진 클래스는 기존의 클래스의 메소드, 객체변수 를 그대로 가지고 있다.
상속받은뒤, 새로운 객체변수, 메소드 추가 할수 있다.
상속받은뒤, 상속받은 메소드 재정의 가능 (오버라이딩)
기존의 클래스 상속하여 새로운 클래스 정의하는 구문
class 새클래스명(기존의 클래스명)
class 새클래스명(기존클래스1, 기존클래스2, ...) <-- 다중상속 허용
기존의 클래스를 '부모클래스(parent class)' 라고 하고
(혹은 super class, base class ...)
상속받은 클래스를 '자식클래스(child class) 라고 한다
(혹은 sub class, derived class ...)
부모의 메소드를 자식 클래스에서 목적에 맞게 다시 정의하는 것을 말합니다.
class BasicTV:
def __init__(self):
self.power = False
self.channel = 0
def display_info(self):
print(f"전원: {self.power}, 채널: {self.channel}")
class SmartTV(BasicTV): #자식
def __init__(self):
super().__init__() # 1. 부모의 생성자를 호출하여 power, channel 초기화
self.ip = "192.168.0.1" # 2. SmartTV만의 고유 속성 추가
def display_info(self): # 메소드 오버라이딩(재정의)
super().display_info() # 4. 부모의 출력 기능을 먼저 실행 (부모 클래스로 이동)
print(f"IP: {self.ip}") # 5. 추가된 IP 정보 출력
# 2차원 원 Circle
# └─ 3차원 구 (球,Sphere)
# 1. '원' 객체 정의
# 클래스 이름 : Circle
# 생성자 : '반지름(radius)'를 받아서 초기화
# get_area() : 면적을 계산하여 리턴하는 메소드
# get_perimeter() : 둘레을 계산하여 리턴하는 메소드
# 2. '구' 객체 정의 <-- Circle 상속받아 정의
# 클래스 이름 : Cube
# get_area() : 정육면체의 총 면적. 4/3 x pi x r³
# get_volume() : 정육면체의 부피 계산. 4 x pi x r²
import math
# 2차원 Circle 정의
class Circle:
def __init__(self, radius = 0):
self.radius = radius
def get_area(self):
return math.pi * self.radius ** 2
def get_perimeter(self):
return 2 * math.pi * self.radius
#실행해보기
c1 = Circle(10)
print(c1.get_area())
print(c1.get_perimeter())
# Circle 을 상속받아 구(Sphere) 객체 생성
class Sphere(Circle):
def get_volume(self): # 자식 클래스에서 추가되는 메소드
return (4 / 3) * math.pi * self.radius ** 3
def get_area(self): # 자식클래스에서 부모클래스의 메소드를 재정의 '오버라이딩'
return 4 * math.pi * self.radius ** 2
#실행해보기
s1 = Sphere(10)
print(s1.get_area())
print(s1.get_perimeter())
print(s1.get_volume())
상속 관계에서 자식 클래스가 생성자를 정의할 때, 부모의 생성자를 어떻게 처리해야 하는지 단계별로 알아봅니다.
자식 클래스에 __init__이 없으면 파이썬은 자동으로 부모의 __init__을 찾아 실행합니다. 하지만 자식에게 __init__을 만드는 순간, 부모의 것은 덮어씌워져(Overriding) 호출되지 않습니다. 따라서 명시적 호출이 필요합니다.
자식 생성자에서 super().__init__()을 호출하여 부모가 가진 speed 속성을 안전하게 물려받습니다.
class Vehicle:
def __init__(self, speed=0):
print(f'Vehicle 생성 speed={speed}')
self.speed = speed
class Car(Vehicle):
def __init__(self, speed=0, oil=0):
# 부모에게 필요한 speed 값을 전달하며 생성자 호출
super().__init__(speed)
print(f'Car 생성 oil={oil}')
self.oil = oil
Vehicle → Car → HybridCar로 이어지는 상속 체인을 완성해 봅니다.
class HybridCar(Car):
def __init__(self, speed=0, oil=0, battery=0):
# 바로 위 부모인 Car의 생성자를 호출
# Car는 다시 Vehicle의 생성자를 호출하게 됩니다 (상속 체인)
super().__init__(speed, oil)
print(f'HybridCar 생성 battery={battery}')
self.battery = battery
| 상황 | 동작 방식 | 비유 |
|---|---|---|
| 자식에 생성자가 없을 때 | 부모의 생성자가 자동으로 실행됨 | 가업을 그대로 이어받음 |
| 자식에 생성자를 만들 때 | 부모의 생성자는 무시됨 (직접 불러야 함) | 내가 새로운 가업을 시작함 (부모 도움 필요 시 요청) |
| super()의 역할 | 부모 클래스의 메서드/생성자에 접근 | "부모님, 물려주신 기본 세팅은 제가 알아서 할게요" |
h = HybridCar(100, 50, 80)
# 출력 순서:
# Vehicle 생성 speed=100 (최상위 부모부터)
# Car 생성 oil=50
# HybridCar 생성 battery=80 (마지막에 자기 자신)
💡 주의사항
super().__init__()을 호출하지 않으면, 자식 객체는 부모가 정의한 self.speed 같은 변수를 가지지 못하게 됩니다. 나중에 h.speed를 조회할 때 AttributeError가 발생할 수 있으니 꼭 써주는 것이 원칙입니다!
예시
자식이 생성자를 만들지 않은 경우
class Vehicle:
def __init__(self, speed):
print("Vehicle 생성자 실행!")
self.speed = speed
class Car(Vehicle):
pass # 생성자를 만들지 않음
# Car에는 생성자가 없지만, 부모의 것을 빌려와서 사용함
c1 = Car(100)
print(c1.speed) # 결과: 100
자식이 생성자를 만든 경우(오버라이딩)
class Vehicle:
def __init__(self, speed):
self.speed = speed # 부모의 소중한 변수 설정
class Car(Vehicle):
def __init__(self, oil):
self.oil = oil # 자식인 나는 내 변수(oil)만 챙김
c1 = Car(50)
print(c1.oil) # 출력: 50 (잘 됨)
print(c1.speed) # 에러 발생! (AttributeError: 'Car' object has no attribute 'speed')
__로 시작하고 끝나는 특별한 메소드들로, 파이썬 내장 연산자들의 동작을 클래스에 정의할 수 있게 합니다.
| 연산자 | 메소드 | 설명 |
|---|---|---|
| + | __add__ | 덧셈 연산 |
| == | __eq__ | 값 비교 |
| len() | __len__ | 길이 반환 |
| print() | __str__ | 문자열 출력용 |
__repr__: 객체 자체의 표현값 (개발/디버깅용)__str__: 사용자가 보기 편한 문자열 (출력용) class Number:
def __init__(self, number):
self.number = number
def __add__(self, other):
return Number(self.number + other.number)
def __repr__(self):
return str(self.number)
n1, n2 = Number(10), Number(20)
print(n1 + n2) # 30 (__add__에 의해 객체 연산 가능)