Home [파이썬 프로그래밍 기초] 10강 - 객체 지향
Post
Cancel

[파이썬 프로그래밍 기초] 10강 - 객체 지향

💡해당 게시글은 방송통신대학교 정재화 교수님의 '파이썬 프로그래밍 기초' 강의를 개인 공부 목적으로 메모하였습니다.



학습 목표


  • 객체 지향의 개념에 대해 설명할 수 있음
  • 객체 유사성을 도출하여 추상화할 수 있음
  • 클래스와 인스턴스를 정의할 수 있음



주요 용어


  • 객체 지향
    • 객체와 객체 사이의 상호 작용으로 프로그램을 구성하는 프로그래밍 패러다임
  • 클래스
    • 실 세계의 객체에 대한 데이터와 연산을 표현한 단위
  • 초기자
    • 객체의 상태를 초기화하는 특수 메소드
  • 객체 멤버 접근 연산자
    • 객체의 데이터 필드 접근 및 메소드 호출에 사용되는 연산자



강의록


객체 지향의 이해

유사성

image.png

  • 공통적인 것은 미리 만들어 놓고 서로 다른 점만 따로 구현한다면 훨씬 더 효과적인 대형의 프로그램을 개발할 수 있음
  • 하나의 프로그램 내부에서도 서로 다른 객체 사이의 공통점을 또 찾아내 구현하고 다른 점만 별도로 구현

객체 지향의 이해

객체 지향의 개념

  • 객체와 객체 사이의 상호 작용으로 프로그램을 구성하는 프로그래밍 패러다임
  • 프로그램을 유연하고 변경을 쉽게 만들어 대규모 소프트웨어 개발에 사용
  • 객체 지향 패러다임의 특징
    • 추상화
      • 공통의 속성이나 기능을 도출
    • 캡슐화
      • 데이터 구조와 데이터의 연산을 결합
    • 상속
      • 상위 개념의 특징이 하위 개념에 전달
    • 다형성
      • 유사 객체의 사용성을 그대로 유지

객체와 클래스

  • 객체는 추상화와 캡슐화의 결과
  • 실 세계의 사물에 대한 상태(데이터)와 연산(메소드)을 표현한 단위
    • 멤버(데이터 필드, 메소드)는 클래스에 의해 결정

    image.png

    • 클래스를 통해 어떠한 객체를 만들어서 실제 사물을 만들 경우 initializer가 동작하면서 초기화시켜주고 기본 값으로 만들어 주는 역할을 함

클래스 정의

  • 구문 형식

    1
    2
    3
    
      class 클래스_이름:
          # 초기자 정의 (__init__)
          # 메소드 정의
    
    • 함수와 동일하게 정의 되는 메소드
  • 메소드(method)
    • 객체에 대한 행동(연산)을 정의
    • 함수의 정의 및 사용 방법과 동일
  • 초기자(initializer)
    • 객체의 상태를 초기화하는 특수 메소드
    • 항상 __init__ 으로 명명

메소드의 정의

  • 구문 형식

    1
    2
    3
    
      class 클래스_이름:
          def 메소드_이름(self, 매개 변수_리스트):
              # 코드 블럭
    
  • self 매개 변수

    • 모든 메소드의 첫번째 매개 변수
    • 메소드의 구현에 사용되지만 메소드 호출 시 사용되지 않음
    • 객체 자신을 참조하여 클래스 정의에 포함된 멤버에 접근 시 사용
    • 클래스 내부의 변수에 접근할 때 데이터 필드임을 알려줌

원뿔 계산 프로그램 개선

  • 객체 지향 개념이 적용 된 원뿔 클래스

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      # 원뿔 겉넓이 계산 함수 정의
      def rtn_cone_surf(r, h):
        
      # 원뿔 부피 계산 함수 정의
      def rtn_cone_vol(r, h):
        
      # 원기둥 부피 계산 함수 정의
      def rtn_cylinder_vol(r, h):
        
      # 사각형 넓이 계산 함수 정의
      def rtn_rect_area(w, h):
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      # 원뿔 클래스 정의
      class Cone:
          def __init__(self, radius = 20, height = 30): # 초기자 지정
              # 변수 r과 h의 스코프는 __init__ 메소드 내부
              # 지역 변수
              r = radius 
              h = height
        
          def get_vol(self):
              # 원뿔 부피 계산: 1 / 3 * pi * r^2 * h
              return 1 / 3 * 3.14 * self.r ** 2 * self.h
        
          def get_surf(self):
              # 원뿔 겉넓이 계산: pi * r^2 + pi * r * h
              return 3.14 * self.r ** 2 + 3.14 * self.r * self.h # 데이터 필드의 r과 h라는 것을 알려주기 위해 꼭 self.를 앞에 표시해주어야 함
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
      # 원뿔 클래스 정의
      class Cone:
          def __init__(self, radius = 20, height = 30): # 초기자 지정
              # self.r, self.h의 스코프는 클래스 전역
              # self.r, self.h는 인스턴스 변수 (클래스 내 다른 메소드에서도 접근 가능)
              self.r = radius
              self.h = height
        
          def get_vol(self):
              # 원뿔 부피 계산: 1 / 3 * pi * r^2 * h
              return 1 / 3 * 3.14 * self.r ** 2 * self.h
        
          def get_surf(self):
              # 원뿔 겉넓이 계산: pi * r^2 + pi * r * h
              return 3.14 * self.r ** 2 + 3.14 * self.r * self.h
    

클래스 설계

  • UML 클래스 다이어그램 통해 데이터 필드, 생성자, 메소드 표현 방법 표준화
    • 데이터 필드 이름: 데이터 필드 타입
    • 클래스 이름(매개 변수 이름: 매개 변수 타입)
    • 메소드 이름(매개 변수 이름: 매개 변수 타입): 반환 값 타입
    • Unified Modeling Langauage 의 약어로, 표준화 된 모델링 언어를 의미
      • 클래스가 어떻게 구성되어 있는 지를 알 수 있는 표기

원뿔 클래스의 표현

  • UML 클래스 다이어그램

    image.png

    • Cone 데이터 필드와 타입
    • Cone 클래스 이름으로 된 메소드, 생성자, 객체를 생성하려고 할 때 자연스럽게 불러지는 함수

BMI 계산 프로그램

  • 이름, 나이, 몸무게, 키를 사용하여 BMI 수치 및 상태를 반환하는 BMI 클래스를 정의

    image.png

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
      class BMI:
          def __init__(self, name, age, weight, height): # 초기자 지정
              self.name = name # 입력 파라미터에 들어온 값들을 데이터 필드에 넣어주는 작업
              self.age = age
              self.weight = weight
              self.height = height
                
          def get_BMI(self):
              return self.weight / (self.height) / 100 ** 2
            
          def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분
              BMI = self.get_BMI()
                
              if BMI >= 25:
                  return "비만"
              elif BMI >= 23 and BMI < 25:
                  return "과체중"
              elif BMI >= 18.5 and BMI < 23:
                  return "정상"
              else:
                  return "저체중"
    
    • get_BMI에서 반환 된 값을 부르는 방법
      1. 내부의 메소드를 직접 호출

        1
        2
        3
        4
        5
        6
        7
        8
        9
        
         def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분
             if self.get_BMI() >= 25:
                 return "비만"
             elif self.get_BMI() >= 23 and self.get_BMI() < 25:
                 return "과체중"
             elif self.get_BMI() >= 18.5 and self.get_BMI() < 23:
                 return "정상"
             else:
                 return "저체중"
        
      2. 변수에 메소드 반환 값을 저장해 놓고 해당 변수를 호출

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        
         def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분
             BMI = self.get_BMI()
                        
             if BMI >= 25:
                 return "비만"
             elif BMI >= 23 and BMI < 25:
                 return "과체중"
             elif BMI >= 18.5 and BMI < 23:
                 return "정상"
             else:
                 return "저체중"
        

클래스와 인스턴스

원뿔 클래스 활용

  • 원뿔 클래스를 사용하려면?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      # 원뿔 클래스 정의
      class Cone :
          def __init__(self, radius = 20, height = 30):
              self.r = radius
              self.h = height
        
          def get_vol(self) :
              return 1 / 3 * 3.14 * self.r ** 2 * self.h
        
          def get_surf(self) :
              return 3.14 * self.r ** 2 + 3.14 * self.r * self.h
    

객체와 인스턴스

  • 구문 형식

    1
    
      클래스_이름(초기자_파라미터)
    
    • 클래스의 생성자(constructor)를 통해 클래스의 인스턴스를 생성
      • 생성자 호출
    • 객체와 인스턴스는 동일 개념
    • 클래스의 생성자는 클래스의 이름과 동일
    • 클래스의 이름과 초기자의 매개 변수를 사용하여 생성자를 호출
      • 정의했던 설계 도면대로 실제 객체 생성 됨
      • 실체화 된 대상이기 때문에 값 저장, 변형 등이 가능

객체의 생성 과정

1
Cone(20, 30)

image.png

  1. 클래스에 해당하는 객체 생성
  2. __init__() 메소드 호출하여 객체 초기화
    • Cone(20, 30) 호출 시 r=20, h=30 으로 설정
      • 초기자에 있었던 반지름과 높이 값
    • 메모리에 객체가 저장될 수 있는 저장 영역을 만들게 되고 그 다음에 초기자가 실제 처음으로 객체가 만들어졌을 때 기본적으로 실행되어야 하는 여러가지 행동들을 정의하며 세팅

객체의 사용

  • 객체의 데이터 필드 접근 및 메소드 호출
    • 객체 멤버 접근 연산자 (.) 사용
      • 객체로 조작, 연산을 하고 싶다면 객체 참조 변수에 점(.)만 찍으면 됨
  • 객체 접근

    1
    2
    
      객체_참조변수.데이터_필드
      객체_참조변수.메소드(파라미터)
    
    • 객체 참조 변수를 사용하여 객체를 생성하고 접근
      • 생성자를 통해 만들어진 객체에 접근할 수 있는 지칭 도구
    1
    
      객체_참조변수 = 클래스_이름(초기자_파라미터) # 생성자를 통해 만들어진 객체 
    

원뿔 클래스 활용

  • 단위 원뿔과 반지름과 높이가 각각 50, 100인 원뿔의 부피와 겉넓이를 출력하는 프로그램

    image.png

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      unit_cone = Cone() # 객체 참조 변수 = 클래스명(초기자 파라미터), 별도로 정의해주지 않으면 위에서 정의한 기본 값이 적용
      big_cone = Cone(50, 100)
        
      # 멤버에 접근하기 위해서는 연산자 .을 사용
      unit_cone.get_vol() # 부피 구하는 메소드 호출
      unit_cone.get_surf() # 겉넓이 구하는 메소드 호출
        
      print("단위 원뿔의 겉넓이와 부피는", unit_cone.get_surf(), unit_cone.get_vol(), "입니다.")
      print("큰 원뿔의 겉넓이와 부피는", big_cone.get_surf(), big_cone.get_vol(), "입니다.")
    

BMI 클래스 활용

  • 가상의 이름, 나이, 몸무게, 키를 사용하여 BMI 객체를 사용하는 프로그램

    image.png

    1
    2
    3
    
      person1 = BMI("홍길동", 40, 78, 182) # 객체 참조 변수를 만들고 BMI 객체를 호출함
        
      print(person1.name + "님(" + str(person1.age) + "세)의 BMI 수치는", person1.get_BMI(), "결과는", person1.get_status(), "입니다.")
    

객체 지향의 활용

데이터 타입과 객체

1
"Korea National Open University".lower() # 소문자로 변형 되어서 문자열 출력
1
2
3
number = 20
print(type(number))  # <class 'int'>
print(id(number))    # id: 1403902********28
1
2
3
symbol = "파이썬"
print(type(symbol))  # <class 'str'>
print(id(symbol))    # id: 1403892********08
  • 파이썬의 기본 데이터 타입 (int, str 등)도 객체임
    • 모든 변수는 객체
    • 객체 지향형 프로그래밍 언어에서는 모든 것은 다 객체를 통해 이루어짐
  • type() 함수
    • 객체의 타입 확인할 수 있음
  • id() 함수
    • 객체의 고유 식별자(메모리 주소)를 확인할 수 있음

str 메소드

  • .upper(), .lower() 메소드
    • 대/소문자로 변경
  • .title() 메소드
    • 각 단어의 첫 글자를 대문자로 변경
  • .strip(), .rstrip(), .lstrip() 메소드
    • 양쪽/오른쪽/왼쪽의 특정 문자를 제거
  • .replace() 메소드
    • 문자열 특정 부분을 대체
  • .split()
    • 구분자로 분할하여 리스트로 반환
1
2
3
4
"I love python".upper() # "I LOVE PYTHON"
"I love python".replace("o", "i") # "I live pythin"
isymbol = "I love python".replace("o", "i")
# dir(str) # str 객체가 가진 모든 메소드와 속성 확인

원뿔 클래스 개선

  • 멤버 r 또는 h에 음수를 입력하면?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
      # 원뿔 클래스 정의
      class Cone:
          def __init__(self, radius = 20, height = 30) # 초기자 지정
              self.r = radius
              self.h = height
                
          def get_vol(self):
              return vol = 1 / 3 * 3.14 * self.r ** 2 * self.h #데이터 필드의 r과 h라는 것을 알려주기 위해 꼭 self.를 앞에 표시해주어야 함
                
          def get_surf(self):
              return suf = 3.14 * self.r ** 2 + 3.14 * self.r * self.h
                
      unitcone = Cone(50, 100)
      unitcone.r = -50  # 외부에서 데이터 필드에 직접 접근하여 음수 값을 할당하는 것이 가능 -> 부피/겉넓이 계산에 문제 일으킴
    
    • 악의적인 사용자가 Cone 클래스에 접근하지 못하도로 제약을 줄 필요가 있음
      • 나이, 몸무게, 키는 private로 지정해 변경 방지

데이터 필드 감추기

  • 데이터 은닉(Data Hiding)
    • 데이터 필드의 직접 변경을 방지하기 위해 사용자의 직접적 접근을 차단
    • public과 다른 private 데이터 필드로 정의
  • private 데이터 필드
    • 클래스 내부에서만 접근 가능
    • 앞 두 밑줄(__)로 정의

      1
      
         self.__r
      
      1
      
        self.__h
      

접근자와 변경자

  • private으로 정의된 데이터 필드는 객체 외부에서 직접 접근 불가능

    1
    2
    3
    4
    5
    
      File "<ipython-input-7-a73e9d167542>", line 13
      		print(unitcone.__r = - 50)
      					^
      SyntaxError: expression cannot contain assignment,
      perhaps you meant "=="?
    
    • print(unitcone.__r) 와 같은 접근 시 에러 발생
  • private 데이터 필드에 접근하기 위한 메소드
    • 접근자(Accessor)
      • 데이터 필드 반환 (Getter)
    • 변경자(Mutator)
      • 데이터 필드 설정 (Setter)
  • 잘못 된 값으로 객체가 만들어지는 것을 막기 위한 접근자변경자

원뿔 클래스 개선

  • 멤버 __r과 __h에 대한 접근자와 변경자 정의

    image.png

    1. 클래스에 잘못 된 접근 차단하기
    2. 접근자와 변경자 통한 private 데이터 필드 접근
      • 만들어진 객체들이 정상 범위 내에서 동작하도록 해야함
      • 데이터 필드 값 접근 막아야 함
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
      class pCone:
          def __init__(self, radius = 20, height = 30): # 초기자 지정
              if radius > 0 and height > 0:
                  self.__r = radius # private 선언 -> 객체 외부에서는 접근이 불가능한 반지름과 높이 값
                  self.__h = height
        
          def get_vol(self):
              vol = 1 / 3 * 3.14 * self.__r ** 2 * self.__h #데이터 필드의 r과 h라는 것을 알려주기 위해 꼭 self.를 앞에 표시해주어야 함
              return vol
            
          def get_surf(self):
              suf = 3.14 * self.__r ** 2 + 3.14 * self.__r * self.__h
              return suf
            
          def get_radius(self): # 접근자 통한 데이터 필드 반환
              return self.__r
        
          def set_radius(self, radius): # 변경자 통한 데이터 필드 설정
              if radius > 0:# 음수 값이 입력되지 않도록 if문으로 제어
                  self.__r = radius
    
    1
    2
    3
    4
    5
    6
    7
    
      perfect_cone = pCone(100, 200)
        
      perfect_cone.get_vol() # 기존에 보였던 데이터 필드 r, h가 보이지 않음
        
      perfect_cone.r = -50
        
      print(perfect_cone.get_surf())
    

BMI 클래스 활용

  • 가상의 이름, 나이, 몸무게, 키를 사용하여 BMI 객체를 사용하는 프로그램

    image.png

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
      class BMI:
          def __init__(self, name, age, weight, height): # 초기자 지정
              self.__name = name # 입력 파라미터에 들어온 값들을 데이터 필드에 넣어주는 작업
              self.__age = age
              self.__weight = weight
              self.__height = height
                
          def get_BMI(self):
              return self.__weight / (self.__height) / 100 ** 2
            
          def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분
              BMI = self.get_BMI()
                
              if BMI >= 25:            
                  return "비만"
              elif BMI >= 23 and BMI < 25:
                  return "과체중"
              elif BMI >= 18.5 and BMI < 23:
                  return "정상"
              else:
                  return "저체중"
    



연습 문제


  1. 다음 중 객체 지향 패러다임의 특징이라고 할 수 없는 것은?

    a. 개방화

    • 객체 지향 패러다임의 특징
      • 추상화
      • 캡슐화
      • 상속
  2. 다음 코드의 빈 칸에 공통으로 들어가야 하는 것은?

    image.png

    a. self

  3. 다음 코드의 실행 결과는?

    1
    
     "I love python".replace("o", "i").upper()
    

    a. "I LIVE PYTHIN"



학습 정리


  • 객체와 객체 사이의 상호작용으로 프로그램을 구성하는 프로그래밍 패러다임을 객체 지향이라고 함
  • 객체 지향 패러다임의 특징에는 추상화, 캡슐화, 상속, 다형성이 있음
  • 클래스는 실 세계의 사물에 대한 상태(데이터)와 연산(메소드)을 표현한 단위임
  • 클래스는 객체의 행동을 정의하는 메소드와 객체의 상태를 초기화하는 특수 메소드로 구성 됨
  • 모든 메소드의 첫 번째 매개 변수는 self
  • 클래스의 생성자(constructor)호출을 통해 클래스의 인스턴스인 객체가 생성 됨
    • 클래스의 생성자는 클래스의 이름과 동일하며 초기자의 매개 변수를 사용함
  • 객체의 데이터 필드 접근 및 메소드 호출에 객체 멤버 접근 연산자(.)를 사용함
  • 객체의 데이터 필드의 직접 변경을 방지하기 위해 사용자의 직접적 접근을 차단하기 위해 데이터 은닉을 사용함
  • private 데이터 필드는 클래스 내부에서만 접근 가능하며 앞 두 밑줄(__)로 정의함
  • private 데이터 필드에 대해 접근하기 위한 접근자와 변경자 메소드가 정의되어야 함

[파이썬 프로그래밍 기초] 9강 - 함수

[파이썬 프로그래밍 기초] 11강 - 모듈