ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클래스(3)
    Python 2023. 10. 23. 12:38
    클래스의 상속 사용

    사람 클래스로 학생 클래스 만들기

    # class 기반클래스이름:
    #     코드
    # class 파생클래스이름(기반클래스이름):
    #     코드
    
    class Person:
        def greeting(self):
            print('안녕하세요')
    
    class Student(Person):
        def study(self):
            print('공부하기')
    
    james = Student()
    james.greeting()    # 안녕하세요: 기반 클래스 Person의 메서드 호출
    james.study()       # 공부하기: 파생 클래스 Student에 추가한 study 메서드
    
    maria = Person()
    maria.greeting()
    maria.study()       # 에러, Person에는 study 메서드가 없음
    
        maria.study()
        ^^^^^^^^^^^
    AttributeError: 'Person' object has no attribute 'study'

    상속 관계 확인

    class Person:
        def greeting(self):
            print('안녕하세요')
    
    class Student(Person):
        def study(self):
            print('공부하기')
    
    print( issubclass(Student, Person) )

     

    기반 클래스의 속성 사용

    class Person:
        def __init__(self):
            print('Person __init__')
            self.hello = '안녕하세요'
    
    class Student(Person):
        def __init__(self):
            print('Student __init__')
            self.school = '파이썬 강좌'
    
    james = Student()
    print(james.school)
    print(james.hello)    # 기반 클래스의 속성을 출력하려고 하면 에러 발생
    
        print(james.hello)
              ^^^^^^^^^^^
    AttributeError: 'Student' object has no attribute 'hello'
    > 'Student' 객체는 'hello' 속서을 가지고 있지 않음

    + 기반 클래스 초기화

    class Person:
        def __init__(self):
            print('Person __init__')
            self.hello = '안녕하세요'
    
    class Student(Person):
        def __init__(self):
            print('Student __init__')
            super().__init__()    # super()로 기반 클래스의 __init__ 메서드 호출
            self.school = '파이썬 강좌'
    
    james = Student()
    print(james.school)
    print(james.hello)
    
    # 실행 결과
    Student __init__
    Person __init__
    파이썬 강좌
    안녕하세요
    
    # 초기화하지 않아도 되는 경우 (__init__ 메서드 없는 경우)
    
    class Person:
        def __init__(self):
            print('Person __init__')
            self.hello = '안녕하세요'
    
    class Student(Person):
        pass
    
    james = Student()
    print(james.hello)    
    
    # 파생 클래스에 초기화 메서드가 없다면
    # 기반 클래스의 __init__이 자동으로 호출되므로 기반 클래스의 속성 사용 가능

     

    메서드 오버라이딩 사용

    class Person:
        def greeting(self):
            print(self)
            self.hello = '안녕'
    
    class Student(Person):
        def greeting(self):
            print('안녕하세요')
    
    james = Student()
    james.greeting()
    
    # 실행 결과
    안녕하세요

    파생 클래스에서 기반 클래스의 메서드를 새로 정의

    오버라이딩(overriging)은 무시하다, 우선하다란 뜻이 있는데, 말 그대로 기반 클래스의 메서드 무시하고 새로운 메서드 만든단 뜻

    class Person:
        def greeting(self):
            print('안녕')
    
    class Student(Person):
        def greeting(self):
            super().greeting()    # 기반 클래스의 메서드 호출해 중복을 줄임
            print('안녕하세요')
    
    james = Student()
    james.greeting()

    중복되는 기능은 파생 클래스에서 다시 만들지 않고 기반 클래스 기능 사용

    원래 기능 유지하면서 새로운 기능을 덧붙일 때 사용

     

    다중 상속 사용

    class Person:
        def greeting(self):
            print('안녕하세요')
    
    class Univ:
        def manage_credit(self):
            print('학점 관리')
    
    class Undergraduate(Person, Univ):
        def study(self):
            print('공부하기')
    
    james = Undergraduate()
    james.greeting()         # 기반 클래스 Person의 메서드 호출
    james.manage_credit()    # 기반 클래스 Univ의 메서드 호출
    james.study()            # 파생 클래스 Undergraduate에 추가한 study 메서드

     

    다이아몬드 상속

    class A:
        def greeting(self):
            print('A입니다')
    
    class B(A):
        def greeting(self):
            print('B입니다')
    
    class C(A):
        def greeting(self):
            print('C입니다')
    
    class D(B, C):
        pass
    
    x = D()
    x.greeting()
    
    # 실행 결과
    B입니다

     

    메서드 탐색 순서 확인

    클래스.mro()
    
    print( D.mro() )
    
    # 실행 결과
    [<class '__main__.D'>, <class '__main__.B'>,
    <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

    D 다음에 B가 오기 때문에 다이아몬드 상속 코드 실행 결과에서 B가 출력된 것

    파이썬은 다중 상속을 한다면 class D(B, C):의 클래스 목록 중 왼쪽에서 오른쪽 순서로 메서드를 찾음

    > 같은 메서드가 있다면 B가 우선함, 상속 관계가 복잡하게 얽혀 있다면 MRO를 살펴보기

     

    추상 클래스 사용

    # from abc import *
    
    # class 추상클래스이름(metaclass=ABCMeta):
    #     @abstractmethod
    #     def 메서드이름(self):
    #         코드
    
    from abc import *
    
    class StudentBase(metaclass=ABCMeta):
        @abstractmethod
        def study(self):
            pass
    
        @abstractmethod
        def go_to_school(self):
            pass
    
    class Student(StudentBase):
        def study(self):
            print('공부하기')
    
    james = Student()
    james.study()
    
    # 실행 결과
        james = Student()
                ^^^^^^^^^
    TypeError: Can't instantiate abstract class Student with abstract method go_to_school
    > 추상 메서드 go_to_school을 구현하지 않아 student 인스턴스를 만들 수 없음
    +
    class Student(StudentBase):
        def study(self):
            print('공부하기')
        def go_to_school(self):
            print('학교가기')
    
    james = Student()
    james.study()
    james.go_to_school()
    
    # 실행 결과
    공부하기
    학교가기

     

    추상 메서드를 빈 메서드로 만드는 이유

    > 추상 클래스는 인스턴스로 만들 수 없음

    james = StudentBase()
    
    # 실행 결과
        james = StudentBase()
                ^^^^^^^^^^^^^
    TypeError: Can't instantiate abstract class StudentBase with abstract methods go_to_school, study

    추상 클래스는 인스턴스를 만들 수 없으니 추상 메서드도 호출할 일 x

        @abstractmethod
        def study(self):
            pass    # 추상 메서드는 호출할 일이 없으므로 빈 메서드로 만듦
        @abstractmethod
        def go_to_school(self):
            pass    # 추상 메서드는 호출할 일이 없으므로 빈 메서드로 만듦

     

    연습 문제 예제
    # 36.8 연습 문제: 리스트에 기능 추가하기
    # 다음 소스 코드에서 리스트(list)에 replace 메서드를 추가한 AdvancedList 클래스를 작성하세요
    # AdvancedList는 list를 상속받아 만들고, replace 메서드는 리스트에서 특정 값으로 된 요소를 찾아
    # 다른 값으로 바꾸도록 만드세요
    
    class AdvancedList(list):
        def replace(self, old, new):
            while old in self:
                self[self.index(old)] = new
                
    x = AdvancedList([1, 2, 3, 1, 2, 3, 1, 2, 3])
    x.replace(1, 100)
    print(x)
    
    # 실행 결과
    
    [100, 2, 3, 100, 2, 3, 100, 2, 3]
    
    # 36.9 심사 문제: 다중 상속 사용하기
    # 다음 소스 코드에서 동물 클래스 Animal과 날개 클래스 Wing을 상속받아 새 클래스 Bird를 작성해
    # '먹다', '파닥거리다', '날다', True, True가 각 줄에 출력되게 만드세요
    
    class Animal:
        def eat(self):
            print('먹다')
    
    class Wing:
        def flap(self):
            print('파닥거리다')
    
    class Bird(Animal, Wing):
        def fly(self):
            print('날다')
    
    b = Bird()
    b.eat()
    b.flap()
    b.fly()
    print(issubclass(Bird, Animal))
    print(issubclass(Bird, Wing))
    
    # 실행 결과
    
    먹다
    파닥거리다
    날다
    True
    True

     

    두 점 사이의 거리 구하기

    클래스로 점 구현

    class Point2D:
        def __init__(self, x, y):
            self.x = x
            self.y = y    # 클래스로 점 구현
    
    p1 = Point2D(x=30, y=20)
    p2 = Point2D(x=60, y=50)
    
    print('p1: {} {}'.format(p1.x, p1.y))
    print('p2: {} {}'.format(p2.x, p2.y))    # 클래스로 점 두 개 만들기

    피타고라스의 정리로 두 점의 거리 구하기

    a = p2.x - p1.x    # 선 a의 길이
    b = p2.y - p1.y    # 선 b의 길이
    
    # 루트 구현 > math.sqrt(값)
    # 제곱근을 반환, 값이 음수면 에러
    
    import math
    
    c = math.sqrt( (a * a) + (b * b) )    # a * a와 b * b의 제곱근 구하기
    print(c)
    
    # 실행 결과
    p1: 30 20
    p2: 60 50
    42.42640687119285

    sqrt 함수에 값을 넣으면 해당 값의 제곱근을 구해 줌

    # a의 제곱을 표현할 때 거듭제곱(power)를 구하는 pow 함수를 써도 O(math 모듈)
    #math.pow(값, 지수) > 값을 지수만큼 거듭제곱한 값을 반환 
    c = math.sqrt(math.pow(a, 2) + math.pow(b, 2))
    
    #  또는 a ** 2라고 적어서 사용해도 O
    c = math.sqrt( (a ** 2) + (b ** 2) )

    abs() = 절대값 함수

    # 절댓값 함수 abs(), 정수는 절댓값 정수로 반환, 실수는 절댓값을 실수로 반환
    >>> abs(3)
    3
    >>> abs(-3)
    3
    >>>
    # 절댓값 함수(실수) fabs(), 절댓값을 실수로 반환
    >>> import math
    >>> math.fabs(2)
    2.0
    >>> math.fabs(-2)
    2.0
    >>>

     

    연습 문제 예제
    # 37.2번 연습 문제: 사각형의 넓이 구하기
    # 사각형의 넓이가 출력되게 만드세요
    
    class Rectangle:
        def __init__(self, x1, y1, x2, y2):
            self.x1 = x1
            self.y1 = y1
            self.x2 = x2
            self.y2 = y2
    
    rect = Rectangle(x1=20, y1=20, x2=40, y2=30)
    
    width = abs(rect.x2 - rect.x1)
    height = abs(rect.y2 - rect.y1)
    area = width * height
    print(area)
    
    # 실행 결과
    
    200
    
    # 37.3번 심사 문제: 두 점 사이의 거리 구하기
    # 표준 입력으로 x, y 좌표 4개가 입력되어 Point2D 클래스의 인스턴스 리스트에 저장됩니다
    # 여기서 점 4개는 첫 번째 점부터 마지막 점까지 순서대로 이어져 있습니다
    # 첫 번째 점부터 마지막 점까지 연결된 선의 길이가 출력되게 만드세요
    
    import math
    
    class Point2D:
        def __init__(self, x=0, y=0):
            self.x = x
            self.y = y
    
    length = 0.0
    p = [ Point2D(), Point2D(), Point2D(), Point2D() ]
    p[0].x, p[0].y, p[1].x, p[1].y, p[2].x, p[2].y, p[3].x, p[3].y = map(int, input().split())
    
    for i in range( len(p)-1 ):
        a = p[i+1].x - p[i].x
        b = p[i+1].y - p[i].y
        length += math.sqrt( math.pow(a, 2) + math.pow(b, 2) )
    
    print(length)
    
    # 실행 결과
    
    10 10 20 20 30 30 40 40    # 표준 입력
    42.42640687119285          # 표준 출력
    
    100 100 200 200 300 300 400 400    # 표준 입력
    424.26406871192853                 # 표준 출력

    'Python' 카테고리의 다른 글

    이터레이터(반복자)  (0) 2023.10.24
    예외 처리  (0) 2023.10.23
    클래스(2)  (0) 2023.10.18
    클래스(1)  (0) 2023.10.18
    클로저  (0) 2023.10.17
Designed by Tistory.