ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 81 - 83 (파이썬) 강의 정리 포기, 코드 복붙
    study with Q - 파이썬 2024. 9. 1. 19:22

    추가적인 요청

    1) 비교연산자를 사용하게 해주쇼

    2) + 연산자를 사용하게 해주쇼

    3) print() 함수를 일반적인 형태로 사용할 수 있게 해주쇼

     

    물론 이런 요청은 터무니 없기에 무시해야 하지만... 실습을 위해 꾹 참고 해봅시다.

     

    참고로) 특수 메소드

    메소드 사용
    __eq__ self = other equals
    __ne__ self != other not equals
    __gt__ self > other greater than
    __ge__ self >= other greater than or equal to
    __lt__ self < other less than
    __le__ self <= other less than or equal to

     

     

    # 81강 코드 -  코드 복사

    class Student:
        def __init__(self, 이름, 국어, 영어, 수학, 과학):
            self.이름 = 이름
            self.국어 = 국어
            self.영어 = 영어
            self.수학 = 수학
            self.과학 = 과학
        def sum(self):
            return self.국어 + self.수학 + self.영어 + self.과학
        def average(self):
            return self.sum() / 4
        def print(self):
            print(self.이름, self.sum(), self.average(), sep="\t")
        def __str__(self):
            return f"{self.이름}\t{self.sum()}\t{self.average()}"
        def __eq__(self, 다른대상): # self == 다른대상
            if type(다른대상) == Student:
                return self.sum() == 다른대상.sum()
            elif type(다른대상) == int:
                return self.sum() == 다른대상
            else:
                raise "같은 자료형을 비교해주세요"
        def __ne__(self, 다른대상): # self != 다른대상
            if type(다른대상) == Student:
                return self.sum() != 다른대상.sum()
            elif type(다른대상) == int:
                return self.sum() != 다른대상
            else:
                raise "같은 자료형을 비교해주세요"
        def __gt__(self, 다른대상): # self > 다른대상
            if type(다른대상) == Student:
                return self.sum() > 다른대상.sum()
            elif type(다른대상) == int:
                return self.sum() > 다른대상
            else:
                raise "같은 자료형을 비교해주세요"
        def __ge__(self, 다른대상): # self >= 다른대상
            if type(다른대상) == Student:
                return self.sum() >= 다른대상.sum()
            elif type(다른대상) == int:
                return self.sum() >= 다른대상
            else:
                raise "같은 자료형을 비교해주세요"
        def __lt__(self, 다른대상): # self < 다른대상
            if type(다른대상) == Student:
                return self.sum() < 다른대상.sum()
            elif type(다른대상) == int:
                return self.sum() < 다른대상
            else:
                raise "같은 자료형을 비교해주세요"
        def __le__(self, 다른대상): # self <= 다른대상
            if type(다른대상) == Student:
                return self.sum() <= 다른대상.sum()
            elif type(다른대상) == int:
                return self.sum() <= 다른대상
            else:
                raise "같은 자료형을 비교해주세요"
    
    class StudentList:
        def __init__(self):
            self.__students = []
        def add(self, student):
            self.__students.append(student)
        def print(self):
            print("이름", "총점", "평균", sep="\t")
            for student in self.__students:
                student.print()
        def __str__(self):
            output = "이름\t총점\t평균\n"
            for student in self.__students:
                output += f"{str(student)}\n"
            return output.strip()
        def clone(self):
            output = StudentList()
            for student in self.__students:
                output.add(student)
            return output
        def __add__(self, 다른대상):
            output = self.clone()
            output.add(다른대상)
            return output
    
    students = StudentList()
    students += Student("인성", 87, 88, 98, 95)
    students += Student("구름", 92, 98, 97, 98)
    students.add(Student("별이", 76, 96, 95, 90))
    print(students)
    
    # 값 객체 예
    class CmLength:
        # 유효한 값만 객체로 만들게 조건문을 걸었습니다.
        def __init__(self, cm):
            if cm < 0:
                raise "길이는 0 이상으로 지정해야 합니다."
            self.__length = cm
        # 이게 뭔지는 다다음 강의에서 자세하게 다루겠습니다.
        def get():
            return self.__length
        # __sub__, __mul__, __truediv__, __floordiv__ 등도 비슷하게 구현하면 됩니다.
        def __add__(self, 다른대상):
            if type(다른대상) != CmLength:
                raise "길이 단위를 통일해주세요!"
            return CmLength(self.get() + 다른대상.get())
        # 다른 비교 연산자도 다음과 비슷하게 구현하면 됩니다.
        def __eq__(self, 다른대상):
            if type(다른대상) != CmLength:
                raise "같은 자료형끼리만 비교할 수 있습니다."
            return self.get() == 다른대상.get()
        def __ne__(self, 다른대상):
            return not (self == 다른대상)
    
    CmLength(3) + CmLength(10)

     

     


     

    #82강

     

    캡슐화

    : 객체를 사용하는 사람이 바꾸지 못하게 변수와 함수를 숨기는 작업

     

    class Circle:
      def __init__(self, 반지름):
        if 반지름 <0 : #방어코드
          raise TypeError("반지름은 양수로 입력하시오.")
        self.반지름 = 반지름
        self.원주율 = 3.14
      def 원의둘레(self):
        return 2 * self.원주율 * self.반지름
      def 원의넓이(self):
        return self.원주율 * (self.반지름 **2)
    
    circle = Circle(10)
    print(circle.원의둘레())
    print(circle.원의넓이())
    >>>
    62.800000000000004
    314.0
    
    class Circle:
      def __init__(self, 반지름):
        if 반지름 <0 :
          raise TypeError("반지름은 양수로 입력하시오.")
        self.반지름 = 반지름
        self.원주율 = 3.14
      def 원의둘레(self):
        return 2 * self.원주율 * self.반지름
      def 원의넓이(self):
        return self.원주율 * (self.반지름 **2)
    
    circle = Circle(-3)
    print(circle.원의둘레())
    print(circle.원의넓이())
    >>>
    TypeError: 반지름은 양수로 입력하시오.

     

    그런데

     

    class Circle:
      def __init__(self, 반지름):
        if 반지름 <0 :
          raise TypeError("반지름은 양수로 입력하시오.")
        self.반지름 = 반지름
        self.원주율 = 3.14
      def 원의둘레(self):
        return 2 * self.원주율 * self.반지름
      def 원의넓이(self):
        return self.원주율 * (self.반지름 **2)
    
    circle = Circle(3)
    circle.반지름 = -3      #음수 입력이 가능해져버림
    print(circle.원의둘레())
    print(circle.원의넓이())
    >>>
    -18.84 
    28.26

     

    그래서 캡슐화 - 인스턴스 함수 앞에 __를 붙여서 구현한다.

    class Circle:
      def __init__(self, 반지름):
        if 반지름 <0 :
          raise TypeError("반지름은 양수로 입력하시오.")
        self.__반지름 = 반지름    #이렇게 __를 넣어주면
        self.원주율 = 3.14
      def 원의둘레(self):
        return 2 * self.원주율 * self.반지름
      def 원의넓이(self):
        return self.원주율 * (self.반지름 **2)
    
    circle = Circle(3)
    print(circle.__반지름)  #프린트를 해보려고 해도
    circle.__반지름 = -3
    print(circle.원의둘레())
    print(circle.원의넓이())
    >>>
    AttributeError: 'Circle' object has no attribute '__반지름' #이렇게 나온다

     

     

    # 겟터와 셋터

      def get_반지름(self) :
        return self.__반지름
      def set_반지름(self, value) :
        self.__반지름 = value

     

    추가하면

    class Circle:
      def __init__(self, 반지름):
        if 반지름 <0 :
          raise TypeError("반지름은 양수로 입력하시오.")
        self.__반지름 = 반지름
        self.__원주율 = 3.14
      def get_반지름(self) :
        return self.__반지름
      def set_반지름(self, value) :
        if value <0:
          raise TypeError("반지름이 양수가 아녀.")
        self.__반지름 = value
      def 원의둘레(self):
        return 2 * self.__원주율 * self.__반지름
      def 원의넓이(self):
        return self.__원주율 * (self.__반지름 **2)
    
    circle = Circle(10)
    print(circle.get_반지름())
    circle.set_반지름(20)
    print(circle.원의둘레())
    print(circle.원의넓이())
    
    >>>
    10 					#현재 반지름
    125.60000000000001	#새로 세팅한 반지름으로 계산한 원의 둘레
    1256.0				#새로 세팅한 반지름으로 계산한 원의 넓이

     

    circle.set_반지름(-20)과 같이 음수로 입력하면 TypeError: 반지름이 양수가 아녀.가 나온다.

     

    겟터와 셋터의 효능

    1) 인스턴스 변수와 함수 앞에 __를 붙이면 외부로부터 숨길 수 있다.

    2) 1)로 인해 외부에서 부정한 값이 들어오는 것을 막을 수 있다.

    3) aka 잘못된 객체가 존재하는 것 자체를 막을 수 있다.

    4) 버그의 발생을 차단하여 유지보수성이 좋아진다.

    5) 몸이 튼튼해지고 이직 때까지 건강하게 살 수 있다.

     

    # 추가 분파 (1) : 비파괴적이 짱짱교

    1) 스택에 있는 서로 다른 이름들이 힙에 있는 하나의 객체를 가리키면 어떤 변수가 어떤 값을 변경하는지 추적하기 어려움. 버그가 발생하면 여러 부분을 확인해야 함.

    2) 비파괴적으로 동작하면 동시성 프로그래밍과 관련된 많은 문제를 해소할 수 있음. (은 아주 나중에 배우거나 영영 배우지 못하겠지.)

     def set_반지름(self, value) :
        if value <0:
          raise TypeError("반지름이 양수가 아녀.")
        self.__반지름 = value
        
    #비파괴적 짱짱교는 set_반지름(self, value)를 다음과 같이 쓴다.
     
     def set_반지름(self, value) :
        return Circle(Value)

     

     

    # 추가 분파 (2) : 값의 본질을 보시오-교

    circle.반지름 = 20
    print(circle.원의둘레)
    print(circle.원의넓이)
    # 이렇게도 입력하게 해달라 달라

    → 우리는 그것을 프로퍼티라고 부르기로 했어요.

    더보기
    class Circle:
      def __init__(self, 반지름):
        if 반지름 <0 :
          raise TypeError("반지름은 양수로 입력하시오.")
        self.__반지름 = 반지름
        self.__원주율 = 3.14
      @property
      def 반지름(self) :
        return self.__반지름
      @반지름.setter
      def 반지름(self, value) :
        if value <0:
          raise TypeError("반지름이 양수가 아녀.")
        self.__반지름 = value
      @property
      def 원의둘레(self):
        return 2 * self.__원주율 * self.__반지름
      @property
      def 원의넓이(self):
        return self.__원주율 * (self.__반지름 **2)
    
    circle = Circle(10)
    circle.반지름
    circle.반지름 = 20
    print(circle.원의둘레)
    print(circle.원의넓이)
    >>>
    125.60000000000001
    1256.0

    ※ 음수로 입력하면 예외가 발생함

     


    #83강

     

    배경 :  멋있게 원의 넓이를 출력하는 코드를 만들고 싶음

    class Circle:
      def __init__(self, radius):
        self.pi = 3.14
        self.radius = radius
      def area(self):
        return self.radius*self.radius*self.pi
      def print_area(self):
        print("="*10)
        print("~"*10)
        print("="*10)
        print(f"원의 반지름: {self.radius}")
        print(f"넓이: {self.area()}")
        print("="*10)
        print("~"*10)
        print("="*10)
    
    circle = Circle(10)
    circle.print_area()
    >>>
    ==========
    ~~~~~~~~~~
    ==========
    원의 반지름: 10
    넓이: 314.0
    ==========
    ~~~~~~~~~~
    ==========

     

    정사각형의 넓이를 구하면

    class Square:
      def __init__(self, length):
        self.length = length
      def sq_area(self):
        return self.length**2
      def print_area(self):
        print("*"*10)
        print("~"*10)
        print("*"*10)
        print(f"정사각형 한 변의 길이: {self.length}")
        print(f"넓이: {self.sq_area()}")
        print("*"*10)
        print("~"*10)
        print("*"*10)
    
    square = Square(10)
    square.print_area()
    >>>
    **********
    ~~~~~~~~~~
    **********
    정사각형 한 변의 길이: 10
    넓이: 100
    **********
    ~~~~~~~~~~
    **********

     

    그런데 도형마다 이렇게 바꾸는 게 귀찮다. 

     

    # 상속 (inheritance)

     

    # 상속
    class Shape:
        def __init__(self):
            raise "생성자를 구현해주세요."
        def 넓이(self):
            raise "넓이 함수를 구현해주세요. 넓이를 리턴하는 함수를 작성해주세요."
        def 출력보조(self):
            raise "출력 보조 함수를 구현해주세요. 출력 전 한마디를 입력해주세요."
        def 출력(self):
            print("=" * 10)
            print("!" * 10)
            print("=" * 10)
            self.출력보조()
            print(f"넓이: {self.넓이()}")
            print("=" * 10)
            print("!" * 10)
            print("=" * 10)
    
    class Circle(Shape):
        def __init__(self, 반지름):
            self.파이 = 3.14
            self.반지름 = 반지름
        def 출력보조(self):
            print(f"원의 반지름은 {self.반지름}")
        def 넓이(self):
            return self.반지름 * self.반지름 * self.파이
    
    class Square(Shape):
        def __init__(self, 길이):
            self.길이 = 길이
        def 출력보조(self):
            print(f"정사각형 한 변의 길이는 {self.길이}")
        def 넓이(self):
            return self.길이 * self.길이
    
    square = Square(10)
    square.출력()
Designed by Tistory.