[Python] 기초 - 객체 지향 프로그래밍(OOP)

ITmakesmeSoft·2022년 9월 3일
0

PYTHON [BASIC]

목록 보기
9/13
post-thumbnail
post-custom-banner

객체 지향 프로그래밍(OOP; Object-Oriented Programming)

  • 프로그램을 여러 개의 독립된 객체들과 그 객체 간의 상호작용으로 파악하는 프로그래밍 방법.
  • EX) 콘서트(가수 객체, 감독 객체, 관객 객체)

객체지향 프로그래밍이 필요한 이유

  • 현실 세계를 프로그램 설계에 반영(추상화)

객체지향의 장/단점

  • 장점
    • 클래스 단위로 모듈화시켜 개발할 수 있으므로 많은 인원이 참여하는 대규모 소프트웨어 개발에 적합
    • 필요한 부분만 수정하기 쉽기 때문에 프로그램 유지보수가 쉬움
  • 단점
    • 설계 시 많은 노력과 시간이 필요함
      • 다양한 객체들의 상호 작용 구조를 만들기 위해 많은 시간과 노력이 필요
    • 실행 속도가 상대적으로 느림
      • 절차 지향 프로그래밍이 컴퓨터의 처리구조와 비슷해서 실행 속도가 빠름

객체지향의 핵심 4가지

  • 추상화
    • 복잡한 것은 숨기고, 필요한 것만 들어내는 것
      • ‘홍길동’, ’김철민’ ⇒ 사람
      • 앞으로 걷기, 뛰기 ⇒ 움직임
  • 상속(Extends)
    • 두 클래스 사이 부모-자식 관계를 정립하는 것

    • 클래스는 상속이 가능함

    • class ChildClass(ParantClass):

    • 하위 클래스는 상위 클래스에 정의된 속성, 행동, 관계 및 제약조건을 모두 상속받음

    • 부모 클래스의 속성, 메서드가 자식 클래스에 상속되므로, 코드 재사용성이 높아짐

    • 두 클래스 사이에 공통부분을 뽑아 부모 클래스를 만들고 하위클래스에서 상속받으면 메서드를 재사용할 수 있음.

    • 파이썬의 모든 클래스는 object로부터 상속됨

    • 부모 클래스의 모든 요소(속성, 메서드)가 상속됨

    • super()를 통해 부모 클래스의 요소를 호출할 수 있음

    • 메서드 오버라이딩을 통해 자식 클래스에서 재정의 가능함

    • 상속관계에서의 이름공간은 인스턴스, 자식 클래스, 부모 클래스 순으로 탐색

      자세한 내용 자세한 내용2

    • 상속 관련 메서드

      • isinstance(*object, classinfo*)
        • classinfo의 instance이거나 subclass인 경우 True

          class Person:
          		pass
          class Professor(Person):
          		pass
          class Student(Person):
          		pass
          
          # 인스턴스 생성
          p1 = Professor()
          s1 = Student()
          
          print(isinstance(p1, Person)) # True
          print(isinstance(p1, Professor)) # True
          print(isinstance(p1, Student)) # False
          print(isinstance(s1, Person)) # True
          print(isinstance(s1, Professor)) # False
          print(isinstance(s1, Student) # True
      • issubclass(*class, classinfo*)
        • class가 classinfo의 subclass면 True

        • classinfo는 클래스 객체의 튜플일 수 있으며, classinfo의 모든 항목을 검사

          class Person:
          		pass
          class Professor(Person):
          		pass
          class Student(Person):
          		pass
          
          # 인스턴스 생성
          p1 = Professor()
          s1 = Student()
          
          print(issubclass(bool, int)) # True
          print(issubclass(float, int)) # False
          print(issubclass(Professor, Person)) # True
          print(issubclass(Professor, (Person, Student))) # True
      • super()
        • 자식클래스에서 부모클래스를 사용하고 싶은 경우

          class Person:
          		def __init__(self, name, age, number, email):
          				self.name = name
          				self.age = age
          				self.number = number
          				self.email = email
          
          class Student(Person):
          		def __init__(self, name, age, number, email, student_id):
          				# Person 클래스
          				# self.name = name
          				# self.age = age
          				# self.number = number
          				# self.email = email 
          				# super() 메서드를 이용해 간소화할 수 있음
          				super().__init__(name, age, number, email)
          				self.student_id = student_id
    • 다중상속

      • 두 개 이상의 클래스를 상속 받는 경우
      • 상속받은 모든 클래스의 요소를 활용 가능함
      • 중복된 속성이나 메선드가 있는 경우 상속 순서에 의해 결정
      • mro 메서드(Method Resolution Order)
        • 해당 인스턴스의 클래스가 어떤 부모 클래스를 가지는지 확인하는 메서드

        • 기존의 인스턴스 → 클래스 순으로 이름 공간을 탐색하는 과정에서 상속 관계에 있으면 인스턴스 → 자식 클래스 → 부모 클래스로 확장

          class Person:
          		pass
          class Dad(Person):
          		pass
          class Mom(Person):
          		pass
          class FirstChild(Dad, Mom): # Dad -> Mom 순서로 탐색 : [0]->[1]
          		pass
          
          print(FirstChild.mro())
          '''
          [<class '__main__.FirstChild'>, <class '__main__.Dad'>, 
          <class '__main__.Mom'>, <class '__main__.Person'>,<class 'object'>]
          '''
  • 다형성(Polymorphism)
    • 동일한 메서드가 클래스에 따라 다르게 행동할 수 있음을 의미
    • 즉, 서로 다른 클래스에 속해있는 객체들이 동일한 메세지에 대해 다른 방식으로 응답할 수 있음
    • 메서드 오버라이딩(Method-Overriding)
      • 상속받은 메서드를 재정의 ⇒ 덮어쓰기

      • 클래스 상속 시, 부모 클래스에서 정의한 메서드를 자식 클래스에서 변경

      • 부모 클래스의 메서드 이름과 기본 기능은 그대로 사용하지만, 특정 기능을 바꾸고 싶을 때 사용

      • 부모 클래스의 메서드를 실행시키고 싶은 경우 super()를 활용

        class Person:
        		def __init__(self, name):
        				self.name = name
        
        		def talk(self):
        				print(f'반갑습니다. {self.name}입니다.')
        
        class Professor(Person):
        		def talk(self): # 메서드 오버라이딩(덮어쓰기)
        				print(f'{self.name}일세.')
        
        class Student(Person):
        		def talk(self):
        				super().talk() # 상위 클래스인 Person의 talk() 실행
        				print(f'저는 학생입니다.')
        
        p1 = Professor('김교수')
        p1.talk() # 김교수일세.
        
        s1 = Student('이학생')
        s1.talk() # 반갑습니다. 이학생입니다.
        					# 저는 학생입니다.
    • 오버로딩(Overloading)
      • 메서드의 이름은 같고, 매개 변수의 갯수나 타입이 다른 함수를 정의하는것을 의미
      • 파이썬은 kargs*으로 대체 가능(overloading시 오류)
  • 캡슐화
    • 객체의 일부 구현 내용에 대해 외부로부터의 직접적인 엑세스를 차단

      • ex) 주민등록번호
    • 파이썬에서 암묵적으로 존재하지만, 언어적으로는 존재하지 않음

    • 접근 제어자 종류

      • Public Access Modifier
      • Protected Access Modifier
      • Private Access Modifier
    • Public Member

      • 언더바 없이 시작하는 메서드나 속성

      • 어디서나 호출이 가능, 하위 클래스 override 허용

      • 일반적으로 작성되는 메서드와 속성의 대다수 차지

        class Person:
        		def __init__(self, name, age):
        				self.name = name
        				self.age = age
        
        p1 = Person('홍길동', 25)
        print(p1.name) # 홍길동
        print(p1.age) # 25
    • Protected Member

      • 언더바 1개로 시작하는 메서드나 속성

      • 암묵적 규칙에 의해 부모 클래스 내부와 자식 클래스에서만 호출 가능(오류가 발생하진 않음)

      • 하위 클래스 override 허용

        class Person:
        		def __init__(self, name, age):
        				self.name = name
        				self._age = age
        
        		def get_age(self):
        				return self._age
        
        # 인스턴스를 만들고 get_age 메서드를 활용하여 호출할 수 있음
        p1 = Person('홍길동', 25)
        print(p1.name) # 홍길동
        print(p1.get_age()) # 25
        
        # 물론 _age에 직접 접근해도 확인 가능
        # 파이썬에서는 암묵적으로 활용되는 것
        print(p1._age) # 25
    • Private Member

      • 언더바 2개로 시작하는 메서드나 속성

      • 본 클래스 내부에서만 사용이 가능

      • 하위클래스 상속 및 호출 불가능(오류)

      • 외부 호출 불가능(오류)

      • 개발 과정에서 불필요한 변수의 접근을 막기 위함

        class Person:
        		def __init__(self, name, age):
        				self.name = name
        				self.__age = age
        
        		def get_age(self):
        				return self.__age # 본 클래스 내부에서만 호출 가능
        
        # 인스턴스를 만들고 get_age 메서드를 활용하여 호출할 수 있음
        p1 = Person('홍길동', 25)
        print(p1.name) # 홍길동
        print(p1.get_age()) # 25
        
        # __age에 직접 접근 불가
        print(p1.__age)
        # AttributeError: 'Person' object has no attribute '__age'
    • getter 메서드와 setter 메서드

      • 변수에 접근할 수 있는 메서드를 별도로 생성
        • getter 메서드 : 변수의 값을 읽는 메서드
          • @property 데코레이터 사용
        • settet 메서드 : 변수의 값을 설정하는 성격의 메서드
          • @변수.setter 사용
      class Person:
      		def __init__(self,  age):
      				self._age = age
      
      		**@property**
      		def age(self):
      				return self._age # 본 클래스 내부에서만 호출 가능
      
      		**@age.setter**
      		def age(self, new_age):
      				if new_age <= 19:
      						raise ValueError('Too Young')
      						return
      				self._age = new_age
      
      # 인스턴스를 만들어서 나이에 접근하면 정상적으로 출력됨
      p1 = Person(25)
      print(p1.age) # 25
      # p1 인스턴스의 나이를 다른 값으로 바꿔도 정상적으로 반영됨
      p1.age = 33
      print(p1.age) # 33
      p1.age = 19
      print(p1.age) # ValueError : Too Young

      참고

profile
💎 Daniel LEE | SSAFY 8th
post-custom-banner

0개의 댓글