만약 '강아지'를 추상화 한다면 어떻게 할 수 있을까? 모든 강아지위 특성인 (종, 크기, 나이, 털 색깔) 등으로 추상화 할 수 있다.
아래의 사진을 보게되면 강아지를 강아지의 특징인(breed, size, age, color)로 추상화하고 (eat, bark, run) 의 method를 가진 class로 만든것을 볼 수 있고 강아지class로 만들어진 object인 (흰둥이, 갈색이, 나시바) 등은 각각 개별적인 attributes 값을 가지는 것을 볼 수 있다.
위의 강아지의 예를 통해서 class를 어떻게 만드는지 코드로 실습을해보겠다.
class Dog: #class 의 이름은 파스칼케이스로 적는다 ex) MyName, Car 등등
pass
흰둥이 = Dog
흰둥이.breed = "진돗개"
흰둥이.size = "large"
흰둥이.age = 3
흰둥이.color = "White"
print(f"흰둥이의 breed: {흰둥이.breed}, size: {흰둥이.size}, age: {흰둥이.age}, color: {흰둥이.color}")
흰둥이의 breed: 진돗개, size: large, age: 3, color: White
다음과 같이 Dog라는 클래스를 통해 흰둥이라는 객체를 만든것을 확인하고 흰둥이의 attributes인 (breed, size, age, color)을 할당해 주었다. 하지만 위의 코드를 보면 하나의 객체를 만들 때 attributes값을 할당하는데 많은 코드를 쓴것을 볼 수 있다. 이것은 initalize(생성자)로 해결할 수 있다. initalize(생성자)는 객체가 초기화 될때 변수의 시작값을 지정할 수 있다.
생성자는 파이썬에서 def __init__
을 사용하면된다.
class Dog:
def __init__(self, breed, size, age, color):
self.breed = breed
self.size = size
self.age = age
self.color = color
흰둥이 = Dog("진돗개", "lage", 3, "White")
print(f"흰둥이의 breed: {흰둥이.breed}, size: {흰둥이.size}, age: {흰둥이.age}, color: {흰둥이.color}")
흰둥이의 breed: 진돗개, size: lage, age: 3, color: White
위 코드에서 def __init__(self, breed, size, age, color)
에서 self란 생성되는 객체 자기자신을 의미한다.
흰둥이 = Dog("진돗개", "lage", 3, "White")
코드에서 self는 흰둥이를 의미하며 흰둥이.breed 에 "진돗개"라는 값이 할당되게 되는것이다.
클래스의 method는 객체가 하는 행동이라고 생각하면 편하다 코드를 통해 강아지class의 method인 eat, bark를 구현해보겠다.
클래스의 method는 파이썬의 함수를 정의하는것과 동일하다고 생각하면 편하다.
class Dog():
def __init__(self, breed, size, age, color):
self.breed = breed
self.size = size
self.age = age
self.color = color
def eat(self, food):
print(f"{food}를 먹는중 입니다.")
def bark(self, something):
print(f"{something}을 향해 짖는중 입니다.")
흰둥이 = Dog("진돗개", "lage", 3, "White")
흰둥이.eat("water")
흰둥이.bark("갈색이")
water를 먹는중 입니다.
갈색이을 향해 짖는중 입니다.
데이터와 그 데이터를 다르기 위한 수단을 하나의 단위로 묶는것. Class를 만드는것을 통해 구현된다.
부모 클래스의 특징(attributes)과 기능(methods)를 그대로 물려 받는 자식클래스를 만드는것.코드의 재사용성을 높여준다.
군인과 군대의 특기 두가지의 class를 예를 들어 상속성을 설명하겠다.
class Soldier(): #군인 클래스 생성
def __init__(self, 군번, 이름, 입대일, 전역일, 소속):
self.군번 = 군번
self.이름 = 이름
self.입대일 = 입대일
self.전역일 = 전역일
self.소속 = 소속
def vacation(self, date):
print(f"{self.이름} {date}까지 휴가")
class DriverSoldier(Soldier): #군인 클래스의 자식 클래스인 운전병 클래스 생성
def __init__(self, 군번, 이름, 입대일, 전역일, 소속, driver_num):
Soldier.__init__(self, 군번, 이름, 입대일, 전역일, 소속) #Soldier의 initalize 호출
self.driver_num = driver_num
def drive(self, destination):
print(f"{destination}을 향해 운전중입니다.")
#부모클래스의 __init__을 사용하여 initalize
soldier = DriverSoldier(19-71117233, "홍길동", "2019-11-19", "2021-06-03", "3사단", 2017315)
soldier.vacation("2021-12-24")
홍길동 2021-12-24까지 휴가
soldier.drive("서울")
서울을 향해 운전중입니다.
soldier객체는 DriverSoldier클래스로 생성됬지만 Soldier클래스를 상속받아 vacation이란 method를 사용하고 동시에 DriverSoldier클래스에 존재하는 method인 drive도 사용할 수 있는것을 볼 수 있다.
class A:
def a(self):
print("a입니다.")
class B:
def b(self):
print("b입니다.")
class C(A,B):
def c(self):
print("c입니다.")
alphbet = C()
alphbet.a() #A의 method
alphbet.b() #B의 method
alphbet.c() #C의 method
a입니다.
b입니다.
c입니다.
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() #어느 class의 greeting method를 말하는 것인가?
안녕하세요, B입니다.
명확하지 않은 형태의 다중 상속 설계는 가능한 피하는게 좋다.
파이썬에서는 다중 상속 관계에서 탐색의 우선순위를 정한다.
.mro()
: 메서드 탐색 순서.
파이썬에서 미리 정해 놓은 규칙에 따라 자식 클래스에서 특정 메서드를 호출 했을때 메서드의 위치를 탐색하는 순서를 반환
(자식->부모중 왼쪽->부모중 오른쪽->상위의 부모..)
D.mro()
[__main__.D, __main__.B, __main__.C, __main__.A, object]
상속성으로 인해 발생한 상속 클래스 계층관계에서, 같은 이름을 가지는 메서드 들이 서로 다른 동작을 할 수 있음을 의미.
부모클래스와 자식클래스에서 동일한 이름의 메서드가 존재하지만 그 메서드의 실제 동작은 서로 다를 수 있음
overriding를 이용해서 자식 클래스에서 부모클래스의 메서드와 동일한 이름의 메서드를 재정의한다.
class Soldier():
def __init__(self, 군번, 이름, 입대일, 전역일, 소속):
self.군번 = 군번
self.이름 = 이름
self.입대일 = 입대일
self.전역일 = 전역일
self.소속 = 소속
def vacation(self, date):
print(f"{self.이름} {date}까지 휴가")
def train(self):
print("사격훈련중입니다.")
class DriverSoldier(Soldier):
def __init__(self, 군번, 이름, 입대일, 전역일, 소속, driver_num):
Soldier.__init__(self, 군번, 이름, 입대일, 전역일, 소속)
self.driver_num = driver_num
def drive(self, destination):
print(f"{destination}을 향해 운전중입니다.")
def train(self): #method overriding
print("운전훈련중입니다.")
soldier1 = Soldier(20-71117244, "홍길동", "2019-10-01", "2021-04-03", "3사단")
soldier2 = DriverSoldier(19-71117233, "홍길동", "2019-11-19", "2021-06-03", "3사단", 2017315)
soldier1.train() #Soldier class의 method
soldier2.train() #DriverSoldier class의 method
사격훈련중입니다.
운전훈련중입니다.
자식 클래스 내에서 부모 클래스의 내용을 호출할때 사용하는 method
class Rectangle: #직사각형 클래스
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length*self.width
class Square(Rectangle): #직사각형 을 상속받는 정사각형 클래스
def __init__ (self, line):
super().__init__(line, line) #super method 를 사용하여 부모 클래스의 __init__을 이용하여 초기화
square = Square(3)
print(square.length)
print(square.width)
3
3
위의 코드를 보면 square 은 line이라는 하나의 parameter를 가지지만 super() method를 사용해 Rectangle의 __init__
을 가져와 line으로 받는 argument로 각각 length와 width에 할당해 초기화 하는것을 볼 수 있다.
class Cube(Square):
def volume(self):
return super().area()*self.length
cube = Cube(3)
print(cube.volume())
print(cube.length)
print(cube.width)
27
3
3
위의 코드는 super()method를 사용해 Square의 area()함수를 호출해 사용했다. 그리고 Cube 는 Square를 상속받고 Square는 Rectangule 을 상속받았기 때문에 Cube클래스를 통해 만들어진 객체인 cube는 length와 width 두개의 attributes를 가진다