MCP - 7일차(Class)

Jun·2026년 2월 14일

MCP

목록 보기
10/20

[Python] 파이썬 객체지향 프로그래밍(OOP) 기초 정리

1. 클래스 정의와 인스턴스 생성

클래스는 새로운 타입을 정의하는 '붕어빵 틀'과 같습니다. 이 틀을 통해 만들어진 실체를 '객체' 또는 '인스턴스'라고 부릅니다.

클래스 정의 및 객체 생성

class Cookie:
        pass

    # 인스턴스 생성
    a = Cookie()
    print(type(a))  # <class '__main__.Cookie'>

2. 객체의 속성과 동작

  • 속성(Attribute): 객체가 가지는 변수 (가로, 세로, 이름 등)
  • 동작(Method): 객체가 수행하는 함수 (넓이 구하기, 걷기 등)

객체변수(instance variable)

객체변수앞에서 말한 속성값과 같은 뜻입니다. 속성값이라고 불리고, 멤버 변수 혹은 필드라고 불립닏다.

생성자 (Constructor): __init__

객체가 생성될 때 자동으로 호출되며, 주로 속성을 초기화하는 역할을 합니다.

self의 이해

메소드의 첫 번째 매개변수는 항상 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
    

3. 클래스 변수 vs 인스턴스 변수

  • 인스턴스 변수: 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 명

4. 상속 (Inheritance)

  • 기존 클래스(부모)의 기능을 그대로 물려받아 새로운 클래스(자식)를 만드는 것입니다.
    코드 재사용성이 높아집니다.

  • 기존의 만들어진 클래스를 상속받아 새로운 클래스 정의 가능합니다.

  • 상속받아 만들어진 클래스는 기존의 클래스의 메소드, 객체변수 를 그대로 가지고 있다.

  • 상속받은뒤, 새로운 객체변수, 메소드 추가 할수 있다.

  • 상속받은뒤, 상속받은 메소드 재정의 가능 (오버라이딩)


기존의 클래스 상속하여 새로운 클래스 정의하는 구문

class 새클래스명(기존의 클래스명)
class 새클래스명(기존클래스1, 기존클래스2, ...)  <-- 다중상속 허용
  • 기존의 클래스를 '부모클래스(parent class)' 라고 하고
    (혹은 super class, base class ...)

  • 상속받은 클래스를 '자식클래스(child class) 라고 한다
    (혹은 sub class, derived class ...)


상속과 오버라이딩(Overriding)

부모의 메소드를 자식 클래스에서 목적에 맞게 다시 정의하는 것을 말합니다.

    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 정보 출력

5. 클래스 설계 원칙 (IS-A vs HAS-A)

  • IS-A (상속): "~은 ~이다" 성립 시 (예: 자동차는 탈것이다 -> Car IS-A Vehicle)
  • HAS-A (포함): "~은 ~을 가지고 있다" 성립 시 (예: 자동차는 타이어를 가진다 -> 속성으로 정의)

예제

# 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())

상속에서의 생성자 호출과 super() 완벽 가이드

상속 관계에서 자식 클래스가 생성자를 정의할 때, 부모의 생성자를 어떻게 처리해야 하는지 단계별로 알아봅니다.


1. 생성자 상속의 기본 원리

자식 클래스에 __init__이 없으면 파이썬은 자동으로 부모의 __init__을 찾아 실행합니다. 하지만 자식에게 __init__을 만드는 순간, 부모의 것은 덮어씌워져(Overriding) 호출되지 않습니다. 따라서 명시적 호출이 필요합니다.


2. 코드 분석 및 완성

① 부모 생성자 명시적 호출

자식 생성자에서 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

② 3단계 상속 구조 완성 (HybridCar)

VehicleCarHybridCar로 이어지는 상속 체인을 완성해 봅니다.

    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

3. 핵심 포인트 정리

상황동작 방식비유
자식에 생성자가 없을 때부모의 생성자가 자동으로 실행됨가업을 그대로 이어받음
자식에 생성자를 만들 때부모의 생성자는 무시됨 (직접 불러야 함)내가 새로운 가업을 시작함 (부모 도움 필요 시 요청)
super()의 역할부모 클래스의 메서드/생성자에 접근"부모님, 물려주신 기본 세팅은 제가 알아서 할게요"

4. 실행 결과 (HybridCar 생성 시)



    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')

6. 매직 메소드 (Magic Method)

__로 시작하고 끝나는 특별한 메소드들로, 파이썬 내장 연산자들의 동작을 클래스에 정의할 수 있게 합니다.

연산자메소드설명
+__add__덧셈 연산
==__eq__값 비교
len()__len__길이 반환
print()__str__문자열 출력용

repr vs 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__에 의해 객체 연산 가능)
profile
Hard Trying

0개의 댓글