OOP 기초개념
.
그림, 실습코드 등 학습자료 출처 : https://github.com/ythwork
-
OOP는 object oriented programming를 의미한다.
-
추상화기법으로 추상화를 객체를 통해서 구현하는 것이다.
-
객체 = 변수 + 함수
-
관련있는 변수(데이터)와 관려있는 함수(기능,행동)를 하나로 모아두는 것
-
oop를 구현할 때는 class로 구현한다.
(참고로 자바는 클래스를 구현하지는 않는다. 그래서 자바로 클래스를 구현하려면 closer를 쓰면된다.)
- 예를 들어서 아래와 같이 사람이라는 클래스를 파이썬 코드로 구현해보자
# 사람 클래스
# 멤버 : 어떤 객체가 가지는 특성값
# 메서드 : 객체가 가지는 기능을 표현
class Person:
# __init__은 생성자라고 하며 객체가 생성할때 이 기능으로 만든다.
def __init__(self, name, age, height):
# 사람이라면 누구나 가지고 있는 특성에 대한 값을 정의
# 사람마다 특성은 갖지만 특성값은 사람마다 다르다.
# 아래를 인스턴스 멤버라고 한다.
self.name = name
self.age = age
self.height = height
# 인스턴스 메서드 : 기능 혹은 행동
def get_old(self):
self.age+=1
def walk(self):
print("walking")
## 객체 혹은 인스턴스
## 위에는 사람이 어떻다는 특성을 나타낸것이지 어떤 사람을 나타내지는 않았다.
## 이렇게 생성된 사람을 객체(오브젝트) 또는 인스턴스라고 한다.
kim = Person('cathy',10,180)
park = Person('minsu',20,170)
kim.get_old()
park.get_old()
## 객체와 클래스는 다른 존재이고
## 객체는 클래스를 참조해서 만들게 된다.
## 각각은 서로 다른 메모리 공간에 저장된다.
kim.name
'cathy'
-
위에 구현한 코드는 외부에서 인스턴스 멤버에 바로 접근하는데 사실 이런 경우는 전형적으로 안좋은 케이스라고 할 수 있다. 이렇게 구현하면 안된다.
-
외부에서 어떤 객체의 인스턴스 멤버에 접근할때 바로 접근하지 않고 가능하면 함수 또는 메서드로 접근해야 한다. 인스턴스 멤버에 바로 접근할때는 유저 프로그래머가 실수를 할 수 있기 때문이다.
-
예를 들어 나이를 양수값만 입력해야 하는데 마이너스값으로 입력한다던가, 이름에 숫자를 입력한다던가 이런문제가 발생하면 프로그램 원천적으로 문제가 발생할 수 있다.
-
위에 구현한것처럼 하지 않으려먼 사람 클래스에 get_name이라는 함수를 만들어서 함수로 이름을 호출하면 된다.
class Person:
def __init__(self, name, age, height):
self.name = name
self.age = age
self.height = height
def get_name(self):
return self.name
def set_age(self, age):
if age <= 0:
print("나이를 잘못 입력했습니다.")
return
self.age = age
def get_age(self):
return self.age
def get_old(self):
self.age+=1
def walk(self):
print("walking")
kim = Person('cathy',10,180)
kim.get_name()
'cathy'
-
이렇게 나이를 잘못입력했을때 함수내부에서 걸러주는 기능이 있다면 사용자의 실수를 차단할 수 있다. 그래서 외부에서 인스턴트 멤버에 바로 접근하는 것을 막는 이유다.
-
아래와 같이 프로그램 사용자가 실수로 나이를 -50이라고 입력할 수 있는 경우가 있는데, 위와 같이 프로그램을 구현하면 프로그래밍을 하는 입장에서 원천적으로 이런 실수가 일어나는 것을 막아줄 수 있다.
kim.set_age(-50)
나이를 잘못 입력했습니다.
-
그런데 유저프로그래머들은 대부분 “다 필요없고 그냥 직접 접근하는 방법처럼 쓰고 싶어” 한다.
-
그래서 마치 멤버에 바로 접근하는 것처럼 보이지만 내부적으로는 property라는 것을 이용해서 함수를 호출해서 접근하는 방법을 구현할 수 있다.
-
아래와 같이 setter나 getter라는 것이 있는데 이런 기능을 access function이라고 한다.
-
예를 들어서 setter는 멤버를 변경하고 싶을때 쓸 수 있고
ex) kim.set_age(50)
- 예를 들어서 getter 멤버에 접근하고 싶을때 쓸 수 있다.
ex) yang.get_name(), yang.get_age()
- property를 이용한 person 구현 예시
class Person:
def __init__(self, name, age, height):
self.name = name
self.__age = age
self.height = height
def get_name(self):
return self.name
## 함수이름이 유저 프로그래머가 멤버라고 생각하고 호출하는 이름
## 그냥 property만 붙이면 getter이다.
@property
def age(self):
return self.__age
@age.setter
def age(self,age):
if age <= 0:
print("잘못된 값이 입력되었습니다.")
return
self.__age = age
def get_old(self):
self.age+=1
def walk(self):
print("walking")
kim = Person('cathy',10,180)
kim.age = 20
kim.age
20
[기타 OOP에서 알고 있어야하는 개념]
1) garbage collection
-
메모리 관리에 관한 얘기이다.
-
쓸모 없어진 메모리 관리하는 것으로 파이썬은 reference count로 가비지 컬랙션을 구현했다.
-
C언어는 메모리를 할당해주면 일일히 다 삭제해주는 코드가 필요하다.
2) 파이썬의 reference count
-
ex) a = 10 ==> reference count = 1
-
ex) a = 10, b = 10 ==> reference count = 2
-
ex) a = 10, b = 10, c = 10 ==> reference count = 3
-
ex)
a = 10
b = 10
c = 10
del c
==> reference count = 2
-
이런식으로 변수를 다 삭제해서 더이상 10을 가리키는게 아무것도 없으면 10은 reference count = 0 이 되어 메모리에서 자동으로 삭제된다.
-
참고로 자주 할당하는 데이터는 메모리에 미리 만들어놓았다. 파이선을 만든 개발자들이 예를들어 1이나 작은 숫자들은 아무래도 자주쓰이기 때문에 메모리에 미리 만들어놓았다.
-
reference count 예시
a = 'hello'
import sys
b = a
sys.getrefcount(a)
4
del b
sys.getrefcount(a)
2
del a
sys.getrefcount(a)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-7-54f892929e6e> in <module>
1 del a
2
----> 3 sys.getrefcount(a)
NameError: name 'a' is not defined
3) ADT(Abstract Data Type) 추상자료형
-
어떤 자료구조의 내부구조를 말한다.
-
이 자료구조가 가지는 기능(오퍼레이션), 역할을 의미한다.
-
기능은 결국에는 함수로 구현한다.
-
간단하게 ADT를 정의하자면 내가 사용하는 자료구조의 함수의 사용법이다.
-
실제 정의는 그 내부구조가 어떻게 구현되어 있는지, 기능은 어떻게 되어있는지에 관한 것이다.
-
list.append의 ADT 예시
help(list.append)
Help on method_descriptor:
append(self, object, /)
Append object to the end of the list.