객체 지향 프로그래밍 (OOP)

0

Python

목록 보기
1/5
post-thumbnail

개념과 이론이 잘 정리되어 있는 블로그나 책은 많다.
코드를 통해 직관적으로 빠르게 이해해보자!

객체란 무엇인가?

객관적으로 존재하는 실체이다. Python은 클래스(Class)를 사용해서 객체를 만든다. 클래스에는 속성 (Attributes), 메소드(Method)가 포함될 수 있다.
클래스는 이렇게 속성과 메소드를 묶을 수 있고, 클래스를 선언하여 객체를 만든다. 이후 객체가 메모리에 할당되면 인스턴스(Instance)가 되며, 이를 해당 클래스의 인스턴스라고 부른다.


객체 지향 프로그래밍의 필요성

앞서 본 '객체'라는 개념을 주로 사용 & 활용하는 프로그래밍을 객체 지향 프로그래밍이라고 한다. 기존에는 절차적 프로그래밍(Procedural Programming)을 사용했었다. 말 그대로 코드가 위에서 아래로 순서대로 실행이 된다.
객체 지향 프로그래밍 (Object Oriented Programming)은 기능(함수, 변수)의 재사용과 수정이 용이하도록, 최소 비용으로 최대 효율을 얻을 수 있다. 특히나 대용량 데이터를 다룰 때, 데이터의 유형은 같고 내용만 다르니 반복되는 코드가 존재한다. 이를 더욱 쉽게 처리할 수 있다.

# 절차적 프로그래밍
Jiho = {'name':'jiho', 'age':26, 'grade':'A'}
Jake = {'name':'jake', 'age':24, 'grade':'B'}
Mike = {'name':'mike', 'age':21, 'grade':'C'}

# 객체 지향 프로그래밍
class Person():
	def __init__(self, name, age, grade):
		self.name = name
		self.age = age
		self.grade = grade
	def get_old(self):
		self.age +=1
Jhio = Person('jiho', 26, 'A')
Jake = Person('jake', 24, 'B')
Mike = Person('mike', 21, 'C')

'''
데이터가 적으니 객체 지향 프로그래밍이 더 길어보이지만, 만약 사람이 100명이라면?
절차적 프로그래밍에서는 'name', 'age', 'grade'라는 Key 단어와 Value 단어를
100번 입력해야하지만, 객체 지향 프로그래밍에서는 Class 선언과 Value 단어만
입력하면 된다.

또한, 만약 name이 아닌 call_me 로 바꾸고 싶다면, 절차적 프로그래밍은 name이라는
key값을 100번 수정해야 하지만, 객체 지향 프로그래밍에서는 Person이라는 클래스만
수정해주면 된다. 이처럼 객체 지향 프로그래밍은 재사용과 수정에 용이하다.
'''

객체 지향 프로그래밍의 특징

1. 상속

상속을 해주는 부모 클래스, 상속을 받는 자식 클래스
부모 클래스의 기능(함수, 변수)를 그대로 재사용

class Person(): # 부모 클래스
    def __init__(self, name):
        self.name = name
        print(f'name: {self.name}')

class Teacher(Person): # Person을 상속받았다.
    def work(self):
        print(f'{self.name}의 본분은 teaching 입니다.')

class Student(Person): # Person을 상속받았다.
    def study(self):
        print(f'{self.name}의 본분은 studying 입니다.')

a = Teacher('jiho')
# 출력: name: jiho
'''
Teacher 클래스를 선언할 때, Teacher는 Person으로부터 상속 받았으므로
1. Person의 생성자 함수(__init__)가 실행된다.
2. self.name에 name이 저장되고 --->  3. 'name: jiho' 출력

'''
b = Student('mike') 
# 출력: name: mike

a.work() 
# 출력: jiho의 본분은 teaching 입니다.
b.study() 
# 출력: mike의 본분은 studying 입니다.

print(a.name) #  jiho
print(b.name) # mike

2. 다형성 (오버라이딩/오버로딩)

부모 클래스의 기능(함수, 변수)를 변형하여 사용

class Person():
    def __init__(self, name):
        self.name = name
        print(f'name: {self.name}')


class Teacher(Person):
    def __init__(self, name):
        super().__init__(name) # 부모 클래스의 생성자 함수를 가져온다.
        print('Teacher입니다.') # 자식 클래스의 생성자 함수에 기능을 추가한다.
        
a = Teacher('jiho')
# 출력
# name: jiho
# Teacher입니다.
'''
1. Teacher 클래스가 a로 인스턴스화될 때, Person의 생성자 함수를 가져오게 된다.
2. 부모 클래스에서 self.name = jiho 진행됨.
3. 부모 클래스에서 'name: jiho'를 출력함.
4. 자식 클래스에서 'Teacher'입니다. 를 출력함.
'''

print(a.name) # jiho

3. 캡슐화

  • 객체의 속성과 메소드를 하나로 결합

    아래 코드의 person은 <name, age, _a, __b>라는 속성과, <_check1, __check2>라는 메소드를 결합한 클래스이다.
  • 정보 은닉

    외부로부터의 직접적인 액세스를 차단한다.
    • 언더바 1개 사용 (_)

      class 안에 언더바 1개인 속성이나 메소드는 외부 사용자는 사용하지 말라는 권유의 문법
    • 언더바 2개 사용( __ )

      class 안에 언더바 2개인 속성이나 메소드는 외부에서 확인 및 수정할 수 없고, 클래스 내부에서만 사용 가능하다. (like 지역변수)
    • name mangling

      '_클래스명__함수명'으로 은닉된 정보에 접근 가능하다.
class Person():
  def __init__(self, name, age):
    self.name = name
    self.age = age
    self._a = 'a'
    self.__b = 'b'

  def _check1(self):
    print('_check1 메소드가 실행됨.')

  def __check2(self):
    print('__chcek2 메소드가 실행됨.')

j = Person('jiho', 26)

print(j.name) # jiho
print(j.age) # 26
print(j._a) # a | 접근은 가능하지만 지양하라
print(j.__b) # AttributeError: 'person' object has no attribute '__b'
print(j._Person__b) # b

j._check1() # 출력: _check1 메소드가 실행됨.
j.__check2() # AttributeError: 'person' object has no attribute '__check2'
j._Person__check2() # __chcek2 메소드가 실행됨.

4. 추상화

객체마다 반복적인 개념이나 기능을 요약한다.
보통 상위클래스로 추상클래스를 만들고, 이를 상속 받은 개별 클래스를 생성한다. 추상클래스에는 추상메소드를 선언까지만 하며, 해당 메소드는 상속받은 다른 클래스의 메소드에서 구현된다.
추상클래스를 사용하는 이유?
: 복잡한 대형 프로젝트는 클래스의 기본적인 틀을 만드는 1차적 설계를 추상화시켜놓고, 활용 여부는 차후에 결정하기 위함이다.

from abc import ABC, abstractmethod

class DogHouse(ABC):

    @abstractmethod  
    def create_roof(self, roof_color):  # 지붕 만들기
        pass

    @abstractmethod
    def creat_windows(self, window_count):  # 창문 만들기
        pass

    @abstractmethod
    def creat_space(self, where):  # 공간 사이즈 정하기
        pass

    @property
    def count(self):  # 집에 살 강아지 수
        pass

class MyDogHouse(DogHouse):

    def create_roof(self, roof_color):
        self.roof_color = roof_color

    def creat_windows(self, window_count):
        self.window_count = window_count

    def creat_space(self, where):
        self.where = where

    @property
    def count(self):
        return self.dog_count   
    
    @count.setter
    def count(self, dog_count):
        self.dog_count = dog_count

    def __str__(self):
        return "강아지집 정보\n\n지붕 색: {}\n창문 갯수: {}\n공간: {}\n집에 사는 강아지수: {}".format(
            self.roof_color,self.window_count, self.where, self.dog_count)

my_dog_house = MyDogHouse()

my_dog_house.create_roof("빨강")
my_dog_house.creat_windows(2)
my_dog_house.creat_space("4평")
my_dog_house.count = 3 # count함수의 setter를 이용

print(my_dog_house)
'''
출력:
강아지집 정보

지붕 색: 빨강
창문 갯수: 2
공간: 4평
집에 사는 강아지수: 3
'''

출처: Panda의 IT노트

profile
학습의 마무리는 '나의 언어로 설명하기'가 아닐까?

0개의 댓글