-
클래스의 상속 사용
사람 클래스로 학생 클래스 만들기
# 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 # 표준 출력