빅데이터 국비 교육

[아이티윌 빅데이터 52기] Day 12 Python Basic | 객체지향 프로그래밍의 이해

datahaseo 2025. 10. 22. 11:15

객체지향 프로그래밍의 이해

*모든 출처는 아이티윌 이광호 강사님

 

<학습 목표>

-클래스와 객체

-self와 생성자

-정보은닉

-클래스 상속

 

클래스와 객체

객체는 기본적으로 필요에 따라 다른 변수와 함수를 내장하고 있는 특수한 변수

-명사적 특성과 동사적 특성이 있음

 

-객체를 구성하는 것은 데이터와 기능으로,

데이터는 멤버 변수 같은 변수로, 기능은 메서드 함수로 표현된다

 

-객체는 설계도 역할을 하는 프로그램 소스로, 하나의 클래스로 같은 구조를 가지는 객체를 여러개 생성할 수 있다

ex) 메이플 게임에서 버섯 몹이 있으면, 모두 하나의 클래스에서 만들어졌고,

각 몹들의 특성 변화는 모두 독립적 (공격 받으면 공격 받은 버섯의 hp 만 줄어드는 것처럼)

 

 

 

 

-class 에 속하는 모든 매서드는 첫 파라미터로 self 값 명시 필요

 

 

-객체에 부여된 기능에 접근하는 유형은 세가지

print(객체.멤버변수) 

변수 =객체.멤버변수

객체.(메서드)

 

(클래스는 직접 작동을 못하고 객체에 부여되었을 때 작동하는 개념)

일반적으로는 처음에 클래스 생성시 멤버변수는 None 으로 설정하고 이후에 값을 할당하여 사용

 

 

SELF 와 생성자

-객체가 자기 자신을 가르키는 키워드로

-'우리 집' '우리 아빠' 처럼 같은 클래스에서 서로 호풀할 떄는 SELF 를 통해서 접근해야함

-SELF 는 전역 변수의 역할도 하면서 클래서 안의 모든 매서드가 공유할 수 있다

 

 

 

 

생성자

-객체가 생성될 때 자동으로 실행되는 매서드

-값을 리턴하는 것은 아니고, 생성자의 이름은 __inti__ 으로 (언더바 두번씩) 약속되어 있음 

-각 객체와 멤버변수를 하나씩 설정해주는 것 보다, 생성자를 통해서 객체를 생성하는게 코드의 효율성을 높힐 수 있음

 

 

 

예시

class monster:
  hp:None
  monster_power:None

  #객체의 속성을 일괄 출력하는 메서드
  def state(self):
    print("현재 체력은 {0}, 공격력은 {1}".format(self.hp,self.monster_power))

  #레벨업 -> 모든 속성 멤버 변수들이 증가한다
  def level_up(self):
    self.hp += 10
    self.monster_power +=2
    print("몬스터가 레벨업 하면서 체력은 +10  , 공격력은 +2 올라갔습니다")

   #공격을 받아 hp 가 감소합니다
  def attacked(self,attack):
    self.hp -=attack
    print('공격을 받아 hp 가 {0} 으로 감소합니다'.format(self.hp))


mushroom=monster()
mushroom.hp=100
mushroom.monster_power =20


mushroom.state()
mushroom.level_up()
mushroom.attacked(30)

 

>>

현재 체력은 100, 공격력은 20

몬스터가 레벨업 하면서 체력은 +10 , 공격력은 +2 올라갔습니다

공격을 받아 hp 가 80 으로 감소합니다

 

 

예시2

class Marine:
    name = None
    hp = None

    # 생성자 — 객체가 만들어질 때 자동 실행
    def __init__(self, name, hp):
        self.name = name
        self.hp = hp
        print("[{0}] You wanna piece of me, boy?".format(self.name))

    # 객체의 상태 출력
    def state(self):
        print("[{0}] hp: {1}".format(self.name, self.hp))

    # 레벨업 메서드
    def level_up(self):
        self.hp += 5
        print("[{0}] 레벨업을 하여 체력이 (+5) 증가했습니다.".format(self.name))

    # 공격받을 때 HP 감소
    def attacked(self, enemy_attack):
        self.hp -= enemy_attack
        print("[{0}] 적의 공격을 받아 hp가 {1} 감소했습니다.".format(self.name, enemy_attack))


m1 = Marine("마린1", 100)
m2 = Marine("마린2", 100)

m1.state()
m2.state()

m1.attacked(30)
m2.attacked(20)

m1.state()
m2.state()

m1.level_up()
m2.level_up()

m1.state()
m2.state()

 

 

 

 

 

 

정보 은닉 (캡슐화)

 

 getter 와 setter 는 한쌍으로 존재

이걸 간단하게 표현하는게 프로퍼티

*getteㄱ 가 setter 보다 더 먼저 정의

 

직접 초기화하는게아니라 setter 를 호출한다

 

함수 호출이 아니라

 

 

 

 

 

self.name 이 변수가 아니라 앞에 나온 매서드들을 통해서 값을 리턴받는 것

 

 

 

 

값 하나가 두개를 다 호출하는 경우

 

 

 

 

 

 

클래스 상속

 

class Terran:
  name=None
  hp=None

  def __init__(self,name,hp):
    self.name=name
    self.hp=hp

  
  def info(self):
    return "[%s] HP: %d"%(self.name,self.hp) 
  
  
  
  
  
  
  
  
  
  
  class Marine(Terran): #Marine 은 Terran 을 상속받아 위에 존재하는 생성자와 변수들을 그대로 상속받는다
  def shoot(self,attack):  #기존 Terra 에는 존재하지 않던 새로운 매서드를 정의하여 기능을 확장한다
    return "[%s] 총을 쏘아 %d의 데미지를 입혔습니다" %(self.name,attack) 
  

m=Marine('마린1',45)
print(m.info())
print(m.shoot(100))

 

 

 super() 를 사용한 부모 기능호출하기

 

class Medic(Terran):
  mana=None

  def __init__(self,name,hp,mana):
    super().__init__(name,hp)

    self.mana=mana
  
  def info_ex(self):
    info_msg=super().info()
    info_msg += ", MANA :%d" %self.mana
    return info_msg
  

  def heel(self,target):
    self.mana-+5
    return "[%s] %s의 체력을 회복시킵니다 (mana:-5)"%(self.name,target)
  
md=Medic('메딕1',30,100)
print(md.info_ex())
print(md.heel('마린1'))

 

 

 

 

<오류 발생했던 코드>

class Medic(Terran):
  mana=None

  def __init__(self,name,hp,mana):
    super().__init__(name,hp)

    self.mana=mana
  
  def info_ex(self):
    info_msg=super().info
    info_msg += ", MANA :%d" %self.mana
    return info_msg
  

  def heel(self,target):
    self.mana-+5
    return "[%s] %s의 체력을 회복시킵니다 (mana:-5)"%(self.name,target)
  
md=Medic('메딕1',30,100)
print(md.info_ex())
print(md.heel('마린1'))

 

  def info_ex(self):
    info_msg=super().info
    info_msg += ", MANA :%d" %self.mana
    return info_msg
 

 

이 부분에서 info 를 호출하지 않아 아래와 같은 오류가 발생했음

TypeError: unsupported operand type(s) for +=: 'method' and 'str'

 

오류 메세지의 의미는 문자열을 더하려고 했는데 왼쪽이 함수 (매서드)였다 라는 뜻

이는 info 메서드를 호출하지 않고 그대로 대입해서 발생한 오류

 

super().info 는 함수 객체이고

super().info() 는 함수를 실행한 결과가 문자열임

 

 

 

파이썬에서는 () 가 있으면 호출되어서 실행 결과값을 의미하고

없으면 객체(매서드) 자체를 가리키는 참조

 

 

예를들어서 아래처럼 greet 자체는 객체이지만 greet() 은 실행 후의 결과값을 의미하게 된

def greet(): 
    return "안녕"

greet        # 함수 “객체”를 가리킴 (실행 X)
greet()      # 함수를 “실행” → "안녕"

 

매서드에서도 () 유무에 따라서 결과 값을 실행하는지 안하는지가 나뉘게 된다

s = "abc"
s.upper      # 메서드 객체 (실행 X)
s.upper()    # "ABC"

 

 

 

자식 하위모드에서 새로 정의하면 상속받은 부모로부터의 값 말고도 더 활용할 수있따

 

 

 

 

 

오버라이드

#매서드 오버라이드 > 부모 클래스의 기능 수정하기
class Animal:
  def sound(self):
    print("동물이 소리를 냅니다.")


class Dog(Animal):
  def sound(self):   #부모로부터 상속받은 sound() 매서드를 수정할 수 있다
    print("멍멍!")

a=Animal()
a.sound()

d=Dog()
d.sound()

==============================


#부모 클래스의 기능을 유지하면서 추가적인 기능을 덧붙이는 오버라이드

#부모의 매서드를 오버라이드하는 매서드 안에서는 super() 함수를 통해 재정의되기 전의 원본 기능에 접근할 수 있음



class Animal:
  def sound(self):
    print("동물이 소리를 냅니다")

class Cat(Animal):
  def sound(self):
    super().sound()
    print('야옹')



c=Cat()
c.sound()

 

 

 

 

*불필요한 기능까지 상속받는 몬스터가 생김 (npc 와 대화, 아이템 줍기)

 

 

그래서 하나의 클래스에 너무 여러 기능을 넣기보다 각 기능들을 특징에 따라 카테고리화 해서 관리하고

이로인해 다중 상속이 필요함