Python Class 와 OOP(객체치향 프로그래밍)

32820 단어 pythonpython

객체지향프로그래밍(oop) 의 개념

  • OOP란 Objected-oriented programming의 약자로 attributes 형태로 data를 가질 수 있고 methods 라는 이름으로 그 데이터에 대한 처리를 할 수 있는 코드를 가지고 있는 걸 객체라고 부른다.
  • OOP란 어떤 특정한 기술이나 특정 언어를 지칭하는 것이 아니라 사용하는 언어와 기술과 상관없이 현실세계의 복잡한 문제를 객체라는 개념을 통해서 우리가 작성하는 프로그램에 반영하는 사고체계이다.

객체(object)의 개념

  • OOP에서 객체가 의미하는 것은 결국, 현실세계의 문제들을 구성하는 요소들을 추상화(Abstraction) 하여 프로그램상의 요소를 표현하기 위한 수단이다.
    • 추상화(Abstraction) : 여러 가지 대상들(Objects)이 가지는 핵심적인 특성을 추출하여 대상을 표현하는 것

만약 '강아지'를 추상화 한다면 어떻게 할 수 있을까? 모든 강아지위 특성인 (종, 크기, 나이, 털 색깔) 등으로 추상화 할 수 있다.

Class vs Object

  • class: 객체가 가진 공통된 특성에 대한 추상화된 서술을 의미한다.
  • object: object는 class의 instance로 class를 통해 생성된 실체를 의미한다.

Attributes vs Methods

  • attributes: 객체를 정의하는 특성들
  • methods: 객체가 가진 데이터들을 조작하기 위한 클래스 내의 함수
  • class를 통해 만들어진 객체들은 각각 개별적인 attributes 값을 가진다.

아래의 사진을 보게되면 강아지를 강아지의 특징인(breed, size, age, color)로 추상화하고 (eat, bark, run) 의 method를 가진 class로 만든것을 볼 수 있고 강아지class로 만들어진 object인 (흰둥이, 갈색이, 나시바) 등은 각각 개별적인 attributes 값을 가지는 것을 볼 수 있다.

class 만들기

위의 강아지의 예를 통해서 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를 먹는중 입니다.
갈색이을 향해 짖는중 입니다.

OOP의 장점

  • 복잡한 프로그램을 작성할 경우에도 객체단위로 분할하여 구조화된 코드를 작성할 수 있다.
  • 디버깅이 쉽다.
  • 코드의 재사용성이 높다
  • 코드의 수정 및 유지보수가 쉽다.

OOP의 특징

1.캡슐화(Encapsulation)

데이터와 그 데이터를 다르기 위한 수단을 하나의 단위로 묶는것. Class를 만드는것을 통해 구현된다.

2.상속성(Inheritance)

부모 클래스의 특징(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입니다.
  • The Deadly Diamond of Death(DDD): 일명 "죽음의 다이아몬드" 다중상속 기능을 이용해서 아래와 같은 상속관계를 만든다면?
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]

2.다형성(Polymorphism)

상속성으로 인해 발생한 상속 클래스 계층관계에서, 같은 이름을 가지는 메서드 들이 서로 다른 동작을 할 수 있음을 의미.
부모클래스와 자식클래스에서 동일한 이름의 메서드가 존재하지만 그 메서드의 실제 동작은 서로 다를 수 있음
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
사격훈련중입니다.
운전훈련중입니다.

super()

자식 클래스 내에서 부모 클래스의 내용을 호출할때 사용하는 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를 가진다

좋은 웹페이지 즐겨찾기