2019.03.23 TIL
(TIL은 스스로 이해한 것을 바탕으로 정리한 것으로 오류가 있을 수 있습니다)
# 질문에 답하기.
- 객체지향이란?
- 객체지향의 특징 3가지
OOP를 시작하기 전에 보면 좋은 것을 지난 번에 TIL한 것에서 가져와보았다.
class - 객체를 만들어 내기 위한 틀
class는 객체를 만들어내기 위한 약속이다.
class는 객체의 속성(property)과 동작(method)을 정의한다.
object - class라는 틀을 가지고 만들어낸 실물(ex. 자동차)
파이썬에서의 객체
- 컴퓨터가 보는 객체 : 클래스를 이용해 만들어진 변수와 함수를 가진 메모리 공간
- 우리가 보는 객체 : 현실 세계의 사물을 모델링 한 것
object란?
- 관련 있는 변수와 함수를 한곳에 모아(bundling) 놓은 곳(메모리의 영역)
- 변수 - 상태정보
- "관련 있는" 변수, 함수" "한곳에 모아" 가 중요하다.
- class를 통해 생성되므로 class의 속성을 가지고 있어야 한다.
- 속성(attribute)
- instance member(변수)
- 각자의 객체가 가지는 값(값 = 상태정보)
- init에 보면 변수가 나와 있음
- 같은 속성을 가지고 있으나 속성 값이 다르다.
- 현재 객체의 담고 있는 인스턴스 멤버 정보 보기 acnt._dict_
- instance method(함수)
- 객체가 할 수 있는 행동, 기능
- instance member(변수)
—> 절차지향에서는 전체 프로그램을 다 봐야하지만.
—> 객체지향에서는 단위로 프로그램을 유추해볼 수 있다.
절차지향 vs 객체지향
###procedural vs object-oriented
2개 다 추상화를 하는 기법이다.
- 추상화란?
- 상세한 정보는 무시하고 필요성에 의해 있어야할 정보만을 추림. why?
- 우리가 구현하고 싶은 것들을 설계하기 위해 멤버와 메서드를 뽑아내는 일
procedural : 함수를 이용해 추상화를 했다. 추상화의 도구로 함수를 이용 (절차지향)
- 이 프로그램은 어떤 일을 하는가?
- 기계와 비슷한 사고 방식
- 함수를 이용
object-oriented : 객체를 통해 추상화를 했다.
- 현실세계에서 객체를 나타내려면 변수와 함수만 있으면 된다. 현실 세계를 모델링하거나 프로그램을 구현하는데 이처럼 변수와 함수를 가진 객체를 이용하는 패러다임을 객체지향이라고 한다.
- 현실 세계(에 존재하는 객체(object)를 어떻게 모델링(modeling)할 것인가?
- 객체(object) : 사람, 동물, 자동차 등을 어떻게 프로그램으로 모델링 할 것인가?
- 사람과 비슷한 사고 방식
- 객체를 이용
OOP의 3대 특징
- 캡슐화
- 정보은닉
- 다형성
1. Encapsulation(캡슐화)
정의 : 관련 있는 멤버(변수=데이터)와 메서드(함수=행동)를 하나의 단위(대부분 클래스)로 묶는 것
관련 있는 멤버와 메서드가 중요하다.
하나의 단위 : java, python, c++ 에서는 모두 클래스로 묶지만 꼭 클래스가 아니라도 하나의 단위로만 묶을 수 있다면 OOP로 볼 수 있다.
정보 은닉을 포함
- 멤버와 메서드를 묶으면서 어떤 멤버를 공개 혹은 공개 하지 않을 것인가 결정
- 어떤 메서드를 공개 혹은 비공개 할 것인가?
- 멤버과 메서드를 공개하지 않을 것을 정보 은닉이라고 한다.
- 정보은닉은 캡슐화 안에서 일어나므로 캡슐화에 포함되었다고 생각
2. 정보은닉
정의 : 특정 멤버와 메서드를 공개하지 않을 것
파이썬에서는 완벽한 정보은닉을 지원하지 않는다.
- 그럼 완벽한 정보은닉은 무엇이냐?
- c에서는 private를 통해 정보를 은닉시킴
- 접근조차 못하게 한다. java, c#, c++모두 지원
- 그럼 완벽한 정보은닉은 무엇이냐?
하지만 약간의 기법을 통해 특정 멤버와 메서드가 정보은닉을 바라는 것인지 알 수 있다.
- name-mungling
- self.__ balance = balance —> acnt.__ balance를 하면 실행이 안됨
- __ balance 를 _Account__balance로 바꾸어서 저장하는 것이다.
- 함수에도 __를 붙여서 외부에서 쉽게 호출하지 못하도록 한다.
- 지원을 할려고 노력은 하되 100%지원은 하지 않음
- self.__ balance = balance —> acnt.__ balance를 하면 실행이 안됨
- property
- OOP 호출 전제 조건
- OOP에서는 외부에서 변수(멤버)에 직접 접근하는 것은 절대 금지이다.
- 객체의 멤버에 접근이나 수정할 떄는 반드시 메서드를 이용해야 한다.
- 따라서 객체의 멤버에 접근하기 위해서는 get_ or set_등과 같은 함수를 이용해야 한다.
- 하지만 property를 이용하여 접근을 일관되게 할 수 있다.
- 멤버를 호출하면 내부적으로는 함수를 호출하도록 설계한다.
- 함수를 설계할 때 특정한 정보은닉을 할 수 있다.
- OOP 호출 전제 조건
- name-mungling
- name-mungling과 멤버에 대한 접근
>>> class Account:
>>> def __init__(self, name, money):
>>> self.user = name
>>> self.__balance = money
>>>
>>> def get_balance(self):
>>> return self.__balance
>>>
>>> def set_balance(self, money):
>>> if money < 0:
>>> return
>>> self.__balance = money
>>>
>>> if __name__ == '__main__':
>>> my_acnt = Account("greg", 5000)
>>> my_acnt.__balance = -3000
>>>
>>> print(my_acnt.get_balance())
>>> print(my_acnt.set_balance(6000))
>>> print(my_acnt.get_balance())
>>> print(my_acnt.__dict__)
>>>
>>> 5000
>>> None
>>> 6000
>>> {"user" : "greg", '_Account_balance' : 6000, '__balance : - 3000'}
- name-mungling을 통해 바로 접근할 수 없어졌고, 클래스안에서 멤버 앞에 언더바 2개를 붙이게 되면 이후에 이 객체가 만들어 질 때 멤버의 이름은 _ 클래스 이름 __ 멤버 로 설정된다.
- 객체의 멤버에 접근하기 위해 get_balance와 set_balance 함수를 통해 접근하였다.
- property를 활용해 이를 해결 할 수 있다.
>>> class Person:
>>> def __init__(self, name, money):
>>> self.name = name
>>> self.money = money
>>>
>>> @property
>>> def money(self):
>>> print('getter executed')
>>> self._money = money
>>>
>>> @money.setter
>>> def money(self, money):
>>> print('setter executed')
>>> if money < 0:
>>> print("음수보다 큰 값을 넣어주세요")
>>> return
>>>
>>> self._money = money
>>>
>>> if__name__ == "__main__":
>>> john = Person('john' , 5000)
>>> print(john.__dict__)
>>> john.money = -5000
>>> print(john.money)
>>>
>>> setter excuted
>>> {'name': 'john', '_money': 5000}
>>> setter excuted
>>> 음수보다 큰 값을 넣어주세요
>>> getter excuted
>>> 5000
- \ __ init __ 을 실행하여 객체를 만들 때 money 멤버에 오면 setter 메서드가 실행되면서 _money로 저장이 된다.
- 이러한 방법을 통해 우리는 정보를 은닉하고 멤버에 대한 접근을 일관되게 할 수 있게 된다.
멤버는 어느 메서드에서도 생길 수 있다!!!!
- 파이썬에서는 다른 어떤 함수에서도 멤버가 생성될 수 있다.
- 따라서 안쓰더라도 모든 멤버들은 __init__에 넣어줘라!
- 인스턴스 멤버를 만든다고 하면 되도록이면 생성자에서 None으로 두고 만들어라
setter를 통해 특정 조건에 대해 멤버 생성을 조절 할 수 있다.
- -가 들어오는게 막고 싶다면(특정 조건) 그 기능을 한 함수에 모아서 setter에 집약시킨다.
생성자에 모든 인스턴스 멤버들을 만들기 위해 노력하되 특정 생성자에 대한 생성 조건이 있다고 하면 그것은 하위에 한 함수를 통해 조절한다.
정보은닉은 name-mungling과 property를 함께 사용하여 확실한 은닉을 하기도 한다.
3. polymorphism(다형성)
정의 : 상속받은 같은 인스턴스 메서드를 호출하는데 호출의 주체인 object가 서로 다른 클래스에서 온 인스턴스기 때문에 다른 behavior을 나타낼 때 다형성이라고 한다.
- 상속을 전제로 한다.
- 다형성은 추상클래스로 부터 오기 때문에 추상클래스에 대해 먼저 알아야 한다.
- 추상클래스를 통해 추상메서드를 만들어내면 이후에 만들어지는 객체에서는 추상메서드를 오버라이딩하여 새로운 인스턴스 메서드를 만들어내고, 각각의 메서드들은 다른 behavior을 나타내게 되는데 이를 다형성이라고 한다.
>>>from abc import ABCMeta, abstractmethod
>>>
>>> class Animal(metaclass=ABCMeta):
>>> @abstractmethod
>>> def say(self):
>>>
>>> print('noting')
>>>
>>>
>>> class Lion(Animal):
>>> # def say(self):
>>> # print("어흥")
>>> pass # 이렇게 say를 빼먹으면 상속받은 메서드를 쓰지 않으면 Lion도 추상 클래스가 된다.
>>>
>>> class Duck(Animal):
>>> def say(self):
>>> print("꽥꽥")
>>>
>>> class Dog(Animal):
>>> def say(self):
>>> print("멍멍")
>>>
>>> class Deer(Animal):
>>> def say(self):
>>> print("사슴")
>>>
>>> if __name__ == "__main__":
>>> animals = []
>>> animals.extend((Lion(), Duck(), Deer(), Dog(), Duck()))
>>>
>>> for animal in animals:
>>> animal.say() #"어흥", "꽥꽥", "멍멍", "사슴"
>>>
>>> ani = Animal() # 이 세상에 그냥 동물은 없으므로 이것을 못되게 해야 한다.
>>> ani.say()
- from abc import ABCMeta (abstract base class)
- 추상클래스는 매개변수로 metacalss = ABCMeta를 받아야 한다.
- 추상매서드를 1개 이상 포함하고 있어야 한다.
- 추상클래스를 상속받아 생성된 클래스는 모두 추상매서드를 오버라이딩해야한다.
추상클래스
정의 : 동물은 고양이과, 개과로 나눌 수 있다. 또 고양이과에는 사자, 고양이, 호랑이 등등 더 세분화 되어 들어갈 수 있다. 하지만 단순히 고양이과의 객체를 만들어서는 그 객체를 구체화 시킬 수 없다. 따라서 객체를 만들기에 너무나 추상적이라 객체를 만들 수 없도록 한 것이 추상클래스이다..
[참고] (https://itewbm.tistory.com/entry/%EC%B6%94%EC%83%81%ED%81%B4%EB%9E%98%EC%8A%A4abstract-class%EC%9D%98-%EC%A1%B4%EC%9E%AC-%EC%9D%B4%EC%9C%A0) : 추상클래스의 존재 이유
abstract class의 특징
- 인스턴스를 만들 수 없다.
- abstract method를 가져야 한다.
- 추상 메서드 (= 순수 가상 함수)는 몸체가 없어야 한다.
- 파생 클래스는 추상메서드를 반드시 overriding을 해야 한다.!!!!!!!!!!
- 상속받은 메서드를 사용하지 않으면 그 클래스도 추상 클래스가 된다.(상위)—> 구현을 강제 할 수 있다.
- 함수 시그니처는 함수 인터페이스 , 함수 사용법이다.
- 객체는 공개된 메서드만 가져와서 사용한다.
- 유저가 사용할 수 있는 메서드의 목록 및 사용방법을 보여주는 것을 인터페이스라고 한다.
- 객체에서 인터페이스라고 하면 유저프로그래머는 내부 프로그램을 알 필요가 없다. 공개되어 있는 메서드만 가져다 쓰면된다.
- 이게 객체에서의 인터페이스이다.
- 인터페이스를 공개한다는 말은
- 유저에게는 인터페이스를 제공하고
- 클래스를 상속받아 쓰는 사람들에게는 다형성을 제공해준다.
메서드 오버라이딩(메서드의 재정의)
- 상속 일때만 해당된다.
- 정의 : 상속을 하는데 자식 클래스가 어떤 함수(이미 상속을 받아서 이미 있는 함수)를 replace한 경우
- 부모로부터 부여 받은 함수를 자신에게 맞추어 메서드를 재정의 하는 것
- 메서드 오버라이딩을 통해 구현 가능 한 것
- 객체에 따라 함수 결과 값을 다르게 바꿀 수 있다.
- 함수를 호출하는 객체가 다르므로
- 객체에 따라 함수 결과 값을 다르게 바꿀 수 있다.
- 다형성을 구현하기 위한 기술적인 특징
- 이것을 기반으로 다양한 패턴이 나온다.
- 메서드 오버라이딩을 하는 순간 다 가상 함수라고 생각해도 된다.
- 상속 일때만 해당된다.
- 연산자 오버로딩(메서드의 중복정의)
- 다형성의 한 종류
- 직접 정의한 클래스에서 생성된 객체는 기본적으로 연산이 불가능하다.
- 직접 정의한 클래스의 객체에 +,-,와 같은 일반 연산을 적용하려면 *연산자 오버로딩**을 통해 객체를 연산 가능한 상태로 만들어야 한다. (기존에 있던 연산자의 기능을 바꾸어 중복으로 정의)
- 파이썬에서는 다른 자료형에 적용되는 모든 연산을 사용자가 정의하는 클래스에서 동작할 수 있도록 구현할 수 있다.
'Python' 카테고리의 다른 글
파이썬 18. Iterator와 Generator (0) | 2019.12.28 |
---|---|
파이썬 17. 깊은 복사 얕은 복사 (0) | 2019.12.28 |
파이썬 15. 클래스간의 관계 (0) | 2019.12.28 |
파이썬 14. 코드를 통해 보는 class (0) | 2019.12.28 |
파이썬 13. openpyxl (0) | 2019.12.28 |