OOP란 객체 지향적인 프로그래밍, 즉 C언어와 같은 절차 지향적인 프로그래밍이 아닌 객체의 관점에서 하는 프로그래밍을 의미한다.
대상을 나타내는 단어이다. 예를 들자면 사람, 사물 하나 하나를 객체라고 할 수 있다. 똑같은 사람이거나 사물이라도 모두 생김새가 조금씩 다르기 때문에 객체라고 할 수 있다.
위에서 말했던 객체들이 공통적으로 갖는 속성을 모아서 정의한 것이 클래스라고 할 수 있다. 설계도라고 하기도 한다.
객체와 클래스를 이해하기 쉽게 다음의 그림을 통해 확인해보겠다.
이미지출처 : python-tutorial-classes-and-objects
위의 그림을 통해 확인해보면 자동차의 속성을 가지는 클래스를 통해서 각 3가지의 자동차를 생성한 것을 볼 수 있다.
자동차를 만드는 틀인 클래스에는 자동차 색깔, 자동차 제조사, 자동차 모델명을 속성으로 가지고 있다. 각 속성들의 값을 가지고 만들어진 자동차는 각각의 객체가 되는 것이다.
클래스를 사용하기 위해서는 우선 해당 클래스 타입의 객체(object)를 선언해야 한다. 이렇게 클래스로부터 객체를 선언하는 과정을 클래스의 인스턴스 화라고 한다.
또한, 이렇게 선언된 해당 클래스 타입의 객체를 인스턴스(instance)라고 한다.
즉, 인스턴스란 메모리에 할당된 객체를 의미합니다.
# 자동차 클래스 생성
class Car():
def __init__(self, color, company, model):
self.color = color
self.company = company
self.model = model
# Mustang 객체에 클래스의 각 필드 속성을 입력하여 클래스의 인스턴스화
Mustang = Car(color='Red', company='Ford', model='Mustang')
print(Mustang)
print(id(Mustang))
# 생성된 자동차 객체
# >> <__main__.Car object at 0x00000209DD73D490>
# 할당된 메모리
# >> 2241393317008
캡슐화는 일반적으로 연관있는 변수와 함수를 클래스로 묶는 작업을 말한다.
즉 클래스를 만들 때 클래스를 통해 만들어진 객체가 특정한 목적을 잘 수행할 수 있도록 사용해야할 변수와 그 변수를 가지고 관련성있는 액션을 할 수 있도록 메소드를 클래스에 잘 구성해야한다.
캡슐화의 정보은닉은 실제 구현 내용 일부를 외부에 감추는 효과이다. 클래스의 정보는 접근지정자를 통해 제한(은닉)
할 수 있는데 만약 변경하지 말아야할 중요한 정보가 Public으로 선언되어 있다면 누구든 접근해서 변경할 수 있게 된다. 이런 부분을 Private로 선언하여 데이터를 보호하여 접근을 제한할 수 있다.
이렇게 보호된 변수는 getter나 setter 등의 메서드를 통해서만 간접적으로 접근이 가능하도록 하는 것이 캡슐화의 중요한 목적이다.
class AM():
def __init__(self):
self.public = 'Public'
self.__private = 'Private'
@property
def private(self):
return self.__private
@private.setter
def private(self, private):
self.__private = private
X = AM()
# Private를 통해 변수에 직접적인 접근 제한
print(X.__private)
# >> AttributeError: 'AM' object has no attribute '__private'
# getter, setter를 통해서 접근
print(X.private)
# >>> Private
X.private = 'Change'
print(X.private)
# >>> Change
복잡한 내용에서 핵심적인 개념 및 기능을 요약하는 것을 말한다.
추상화는 구체적인 사물들간의 공통점을 취하고 차이점을 버리는 일반화를 사용하거나 중요한 부분을강조하기 위해 불필요한 세부사항을 제거함으로써 단순하게 만드는 것이다.
토끼, 거북이와 같은 객체가 있다고 한다면 이 객체들은 동물이란 개념으로 추상화할 수 있다.
공통적인 특징을 취하고 차이점을 버린다.
숨을쉰다, 움직인다.
토끼가 뛰고, 거북이가 기어가는 차이점은 버린다.
불필요한 세부사항을 제거함으로써 단순하게 한다.
다리가 네개 있다, 꼬리가 있다.
이외에 토끼는 큰 귀가 있다, 거북이는 등껍질이 있다 등 세부사항 제거
이를 통해 숨을 쉬며, 움직이고, 다리가 네개 있으며, 꼬리가 있다. 와 같은 특징을 통해 동물로 추상화 할수 있다. 동물은 추상클래스(상위 클래스)
가 되고, 이를 상속받아 개별적인 토끼, 거북이 클래스(하위클래스)
를 생성한다.
from abc import * # abc 모듈의 클래스와 메소드를 갖고온다.(abc : abstract base class)
# 추상 클래스
class People(metaclass=ABCMeta):
# 추상 메소드
@abstractmethod # 추상 메소드에는 @abstractmethod를 선언해줘야 함
def charecter(self):
pass # 추상 메소드는 기능 내 실제 실행내용은 없다.
# 상속받는 클래스
class Student(People):
def charecter(self, pow, think, score):
self.pow = pow
self.think = think
self.score = score
print('체력: {0}'.format(self.pow))
print('생각: {0}'.format(self.think))
print('성적: {0}'.format(self.score))
# 상속받는 클래스
class Driver(People):
def charecter(self, pow, think, pay):
self.pow = pow
self.think = think
self.pay = pay
print('체력: {0}'.format(self.pow))
print('생각: {0}'.format(self.think))
print('요금: {0}$'.format(self.pay))
# Student object 생성
peo1 = Student()
print('Student : ')
# Student object 실행
peo1.charecter(30, 10, 'A')
print()
# Driver object 생성
peo2 = Driver()
print('Driver : ')
# Driver object 실행
peo2.charecter(10, 10, 5)
# >> Student :
# >> 체력: 30
# >> 생각: 10
# >> 성적: A
#
# >> Driver :
# >> 체력: 10
# >> 생각: 10
# >> 요금: 5$
상속이란 기존 상위클래스(부모클래스)
에 근거하여 새롭게 하위클래스(자식클래스)
를 정의할 수 있다.
상속을 통해서 코드의 중복을 피할 수 있다는 장점이 있다.
예를 들어 사람이라는 상위클래스를 가진 경우 학생과 직장인이라는 하위클래스는 사람을 상속 받을 수 있다.
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def print_me(self):
print(f'My name is {self.name} and {self.age} years old')
class Student(Person):
def __init__(self, name, age, score):
Person.__init__(self, name, age) # Person 상속
self.score = score
def print_score(self):
print(f'My score is {self.score}$')
class Employee(Person):
def __init__(self, name, age, pay):
Person.__init__(self, name, age) # Person 상속
self.pay = pay
def print_pay(self):
print(f'My pay is {self.pay}$')
p = Person('Mark', 21)
s = Student('Jason', 18, 'A')
e = Employee('Brown', 32, 120)
print('Person:')
p.print_me()
print('Student:')
s.print_me()
s.print_score()
print('Employee:')
e.print_me()
e.print_pay()
# >> Person:
# >> My name is Mark and 21 years old
# >> Student:
# >> My name is Jason and 18 years old
# >> My score is A
# >> Employee:
# >> My name is Brown and 32 years old
# >> My pay is 120$
상속과 비슷한 개념으로 다른 클래스의 일부 기능을 재사용하는 포함이라는 개념도 존재한다.
class Bill():
def __init__(self, description):
self.description = description
class Tail():
def __init__(self, length):
self.length = length
class Duck():
def __init__(self, bill, tail):
self.bill = bill
self.tail = tail
def about(self):
print(
f"This duck has a {self.bill.description} and a {self.tail.length}.")
duck = Duck(Bill('White'), Tail('Black'))
duck.about()
# >> This duck has a White and a Black.
구현되는 하위클래스(자식클래스)
에 따라 클래스를 다르게 처리하는 것을 말한다.
상속과 유사하다고 할 수 있지만 상속은 상위 클래스의 기능(함수, 변수)를 재사용 한다. 하지만 다형성은 상위클래스의 기능을 변경하여(재사용하지 않는다.)
사용한다.
class Person():
def __init__(self, name, age):
self.name = name
self.age = age
def print_me(self):
print(f"Person : My name is {self.name} and {self.age} years old.")
class Student(Person):
def __init__(self, name, age, score):
Person.__init__(self, name, age)
self.score = score
def print_me(self):
print(f"Student : My name is {self.name} and {self.name} years old. Score is {self.score}")
class Employee(Person):
def __init__(self, name, age, pay):
Person.__init__(self, name, age)
self.pay = pay
def print_me(self):
print(f"Employee : My name is {self.name} and {self.age} years old. Pay is {self.pay}$")
p = Person('Andrew', 23)
s = Student('Brown', 18, 'B+')
e = Employee('Charlie', 30, 520)
p.print_me()
s.print_me()
e.print_me()
# >> Person : My name is Andrew and 23 years old.
# >> Student : My name is Brown and Brown years old. Score is B+
# >> Employee : My name is Charlie and 30 years old. Pay is 520$