학습 목표
- 객체 지향의 개념에 대해 설명할 수 있음
- 객체 유사성을 도출하여 추상화할 수 있음
- 클래스와 인스턴스를 정의할 수 있음
주요 용어
- 객체 지향
- 객체와 객체 사이의 상호 작용으로 프로그램을 구성하는 프로그래밍 패러다임
- 클래스
- 실 세계의 객체에 대한 데이터와 연산을 표현한 단위
- 초기자
- 객체의 상태를 초기화하는 특수 메소드
- 객체 멤버 접근 연산자
- 객체의 데이터 필드 접근 및 메소드 호출에 사용되는 연산자
강의록
객체 지향의 이해
유사성
- 공통적인 것은 미리 만들어 놓고 서로 다른 점만 따로 구현한다면 훨씬 더 효과적인 대형의 프로그램을 개발할 수 있음
- 하나의 프로그램 내부에서도 서로 다른 객체 사이의 공통점을 또 찾아내 구현하고 다른 점만 별도로 구현
객체 지향의 이해
객체 지향의 개념
- 객체와 객체 사이의 상호 작용으로 프로그램을 구성하는 프로그래밍 패러다임
- 프로그램을 유연하고 변경을 쉽게 만들어 대규모 소프트웨어 개발에 사용
- 객체 지향 패러다임의 특징
- 추상화
- 공통의 속성이나 기능을 도출
- 캡슐화
- 데이터 구조와 데이터의 연산을 결합
- 상속
- 상위 개념의 특징이 하위 개념에 전달
- 다형성
- 유사 객체의 사용성을 그대로 유지
- 추상화
객체와 클래스
- 객체는 추상화와 캡슐화의 결과
- 실 세계의 사물에 대한 상태(데이터)와 연산(메소드)을 표현한 단위
- 멤버(데이터 필드, 메소드)는 클래스에 의해 결정
- 클래스를 통해 어떠한 객체를 만들어서 실제 사물을 만들 경우 initializer가 동작하면서 초기화시켜주고 기본 값으로 만들어 주는 역할을 함
클래스 정의
구문 형식
1 2 3
class 클래스_이름: # 초기자 정의 (__init__) # 메소드 정의
- 함수와 동일하게 정의 되는 메소드
- 메소드(method)
- 객체에 대한 행동(연산)을 정의
- 함수의 정의 및 사용 방법과 동일
- 초기자(initializer)
- 객체의 상태를 초기화하는 특수 메소드
- 항상
__init__
으로 명명
메소드의 정의
구문 형식
1 2 3
class 클래스_이름: def 메소드_이름(self, 매개 변수_리스트): # 코드 블럭
self 매개 변수
- 모든 메소드의 첫번째 매개 변수
- 메소드의 구현에 사용되지만 메소드 호출 시 사용되지 않음
- 객체 자신을 참조하여 클래스 정의에 포함된 멤버에 접근 시 사용
- 클래스 내부의 변수에 접근할 때 데이터 필드임을 알려줌
원뿔 계산 프로그램 개선
객체 지향 개념이 적용 된 원뿔 클래스
1 2 3 4 5 6 7 8 9 10 11
# 원뿔 겉넓이 계산 함수 정의 def rtn_cone_surf(r, h): # 원뿔 부피 계산 함수 정의 def rtn_cone_vol(r, h): # 원기둥 부피 계산 함수 정의 def rtn_cylinder_vol(r, h): # 사각형 넓이 계산 함수 정의 def rtn_rect_area(w, h):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# 원뿔 클래스 정의 class Cone: def __init__(self, radius = 20, height = 30): # 초기자 지정 # 변수 r과 h의 스코프는 __init__ 메소드 내부 # 지역 변수 r = radius h = height def get_vol(self): # 원뿔 부피 계산: 1 / 3 * pi * r^2 * h return 1 / 3 * 3.14 * self.r ** 2 * self.h def get_surf(self): # 원뿔 겉넓이 계산: pi * r^2 + pi * r * h return 3.14 * self.r ** 2 + 3.14 * self.r * self.h # 데이터 필드의 r과 h라는 것을 알려주기 위해 꼭 self.를 앞에 표시해주어야 함
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# 원뿔 클래스 정의 class Cone: def __init__(self, radius = 20, height = 30): # 초기자 지정 # self.r, self.h의 스코프는 클래스 전역 # self.r, self.h는 인스턴스 변수 (클래스 내 다른 메소드에서도 접근 가능) self.r = radius self.h = height def get_vol(self): # 원뿔 부피 계산: 1 / 3 * pi * r^2 * h return 1 / 3 * 3.14 * self.r ** 2 * self.h def get_surf(self): # 원뿔 겉넓이 계산: pi * r^2 + pi * r * h return 3.14 * self.r ** 2 + 3.14 * self.r * self.h
클래스 설계
- UML 클래스 다이어그램 통해 데이터 필드, 생성자, 메소드 표현 방법 표준화
- 데이터 필드 이름: 데이터 필드 타입
- 클래스 이름(매개 변수 이름: 매개 변수 타입)
- 메소드 이름(매개 변수 이름: 매개 변수 타입): 반환 값 타입
- Unified Modeling Langauage 의 약어로, 표준화 된 모델링 언어를 의미
- 클래스가 어떻게 구성되어 있는 지를 알 수 있는 표기
원뿔 클래스의 표현
UML 클래스 다이어그램
- Cone 데이터 필드와 타입
- Cone 클래스 이름으로 된 메소드, 생성자, 객체를 생성하려고 할 때 자연스럽게 불러지는 함수
BMI 계산 프로그램
이름, 나이, 몸무게, 키를 사용하여 BMI 수치 및 상태를 반환하는 BMI 클래스를 정의
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
class BMI: def __init__(self, name, age, weight, height): # 초기자 지정 self.name = name # 입력 파라미터에 들어온 값들을 데이터 필드에 넣어주는 작업 self.age = age self.weight = weight self.height = height def get_BMI(self): return self.weight / (self.height) / 100 ** 2 def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분 BMI = self.get_BMI() if BMI >= 25: return "비만" elif BMI >= 23 and BMI < 25: return "과체중" elif BMI >= 18.5 and BMI < 23: return "정상" else: return "저체중"
- get_BMI에서 반환 된 값을 부르는 방법
내부의 메소드를 직접 호출
1 2 3 4 5 6 7 8 9
def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분 if self.get_BMI() >= 25: return "비만" elif self.get_BMI() >= 23 and self.get_BMI() < 25: return "과체중" elif self.get_BMI() >= 18.5 and self.get_BMI() < 23: return "정상" else: return "저체중"
변수에 메소드 반환 값을 저장해 놓고 해당 변수를 호출
1 2 3 4 5 6 7 8 9 10 11
def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분 BMI = self.get_BMI() if BMI >= 25: return "비만" elif BMI >= 23 and BMI < 25: return "과체중" elif BMI >= 18.5 and BMI < 23: return "정상" else: return "저체중"
- get_BMI에서 반환 된 값을 부르는 방법
클래스와 인스턴스
원뿔 클래스 활용
원뿔 클래스를 사용하려면?
1 2 3 4 5 6 7 8 9 10 11
# 원뿔 클래스 정의 class Cone : def __init__(self, radius = 20, height = 30): self.r = radius self.h = height def get_vol(self) : return 1 / 3 * 3.14 * self.r ** 2 * self.h def get_surf(self) : return 3.14 * self.r ** 2 + 3.14 * self.r * self.h
객체와 인스턴스
구문 형식
1
클래스_이름(초기자_파라미터)
- 클래스의 생성자(constructor)를 통해 클래스의 인스턴스를 생성
- 생성자 호출
- 객체와 인스턴스는 동일 개념
- 클래스의 생성자는 클래스의 이름과 동일
- 클래스의 이름과 초기자의 매개 변수를 사용하여 생성자를 호출
- 정의했던 설계 도면대로 실제 객체 생성 됨
- 실체화 된 대상이기 때문에 값 저장, 변형 등이 가능
- 클래스의 생성자(constructor)를 통해 클래스의 인스턴스를 생성
객체의 생성 과정
1
Cone(20, 30)
- 클래스에 해당하는 객체 생성
__init__()
메소드 호출하여 객체 초기화Cone(20, 30)
호출 시r=20
,h=30
으로 설정- 초기자에 있었던 반지름과 높이 값
- 메모리에 객체가 저장될 수 있는 저장 영역을 만들게 되고 그 다음에 초기자가 실제 처음으로 객체가 만들어졌을 때 기본적으로 실행되어야 하는 여러가지 행동들을 정의하며 세팅
객체의 사용
- 객체의 데이터 필드 접근 및 메소드 호출
- 객체 멤버 접근 연산자 (
.
) 사용- 객체로 조작, 연산을 하고 싶다면 객체 참조 변수에 점(
.
)만 찍으면 됨
- 객체로 조작, 연산을 하고 싶다면 객체 참조 변수에 점(
- 객체 멤버 접근 연산자 (
객체 접근
1 2
객체_참조변수.데이터_필드 객체_참조변수.메소드(파라미터)
- 객체 참조 변수를 사용하여 객체를 생성하고 접근
- 생성자를 통해 만들어진 객체에 접근할 수 있는 지칭 도구
1
객체_참조변수 = 클래스_이름(초기자_파라미터) # 생성자를 통해 만들어진 객체
- 객체 참조 변수를 사용하여 객체를 생성하고 접근
원뿔 클래스 활용
단위 원뿔과 반지름과 높이가 각각 50, 100인 원뿔의 부피와 겉넓이를 출력하는 프로그램
1 2 3 4 5 6 7 8 9
unit_cone = Cone() # 객체 참조 변수 = 클래스명(초기자 파라미터), 별도로 정의해주지 않으면 위에서 정의한 기본 값이 적용 big_cone = Cone(50, 100) # 멤버에 접근하기 위해서는 연산자 .을 사용 unit_cone.get_vol() # 부피 구하는 메소드 호출 unit_cone.get_surf() # 겉넓이 구하는 메소드 호출 print("단위 원뿔의 겉넓이와 부피는", unit_cone.get_surf(), unit_cone.get_vol(), "입니다.") print("큰 원뿔의 겉넓이와 부피는", big_cone.get_surf(), big_cone.get_vol(), "입니다.")
BMI 클래스 활용
가상의 이름, 나이, 몸무게, 키를 사용하여 BMI 객체를 사용하는 프로그램
1 2 3
person1 = BMI("홍길동", 40, 78, 182) # 객체 참조 변수를 만들고 BMI 객체를 호출함 print(person1.name + "님(" + str(person1.age) + "세)의 BMI 수치는", person1.get_BMI(), "결과는", person1.get_status(), "입니다.")
객체 지향의 활용
데이터 타입과 객체
1
"Korea National Open University".lower() # 소문자로 변형 되어서 문자열 출력
1
2
3
number = 20
print(type(number)) # <class 'int'>
print(id(number)) # id: 1403902********28
1
2
3
symbol = "파이썬"
print(type(symbol)) # <class 'str'>
print(id(symbol)) # id: 1403892********08
- 파이썬의 기본 데이터 타입 (int, str 등)도 객체임
- 모든 변수는 객체
- 객체 지향형 프로그래밍 언어에서는 모든 것은 다 객체를 통해 이루어짐
type()
함수- 객체의 타입 확인할 수 있음
id()
함수- 객체의 고유 식별자(메모리 주소)를 확인할 수 있음
str 메소드
.upper()
,.lower()
메소드- 대/소문자로 변경
.title()
메소드- 각 단어의 첫 글자를 대문자로 변경
.strip()
,.rstrip()
,.lstrip()
메소드- 양쪽/오른쪽/왼쪽의 특정 문자를 제거
.replace()
메소드- 문자열 특정 부분을 대체
.split()
- 구분자로 분할하여 리스트로 반환
1
2
3
4
"I love python".upper() # "I LOVE PYTHON"
"I love python".replace("o", "i") # "I live pythin"
isymbol = "I love python".replace("o", "i")
# dir(str) # str 객체가 가진 모든 메소드와 속성 확인
원뿔 클래스 개선
멤버 r 또는 h에 음수를 입력하면?
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# 원뿔 클래스 정의 class Cone: def __init__(self, radius = 20, height = 30) # 초기자 지정 self.r = radius self.h = height def get_vol(self): return vol = 1 / 3 * 3.14 * self.r ** 2 * self.h #데이터 필드의 r과 h라는 것을 알려주기 위해 꼭 self.를 앞에 표시해주어야 함 def get_surf(self): return suf = 3.14 * self.r ** 2 + 3.14 * self.r * self.h unitcone = Cone(50, 100) unitcone.r = -50 # 외부에서 데이터 필드에 직접 접근하여 음수 값을 할당하는 것이 가능 -> 부피/겉넓이 계산에 문제 일으킴
- 악의적인 사용자가 Cone 클래스에 접근하지 못하도로 제약을 줄 필요가 있음
- 나이, 몸무게, 키는
private
로 지정해 변경 방지
- 나이, 몸무게, 키는
- 악의적인 사용자가 Cone 클래스에 접근하지 못하도로 제약을 줄 필요가 있음
데이터 필드 감추기
- 데이터 은닉(Data Hiding)
- 데이터 필드의 직접 변경을 방지하기 위해 사용자의 직접적 접근을 차단
public
과 다른private
데이터 필드로 정의
private
데이터 필드- 클래스 내부에서만 접근 가능
앞 두 밑줄(
__
)로 정의1
self.__r
1
self.__h
접근자와 변경자
private
으로 정의된 데이터 필드는 객체 외부에서 직접 접근 불가능1 2 3 4 5
File "<ipython-input-7-a73e9d167542>", line 13 print(unitcone.__r = - 50) ^ SyntaxError: expression cannot contain assignment, perhaps you meant "=="?
print(unitcone.__r)
와 같은 접근 시 에러 발생
private
데이터 필드에 접근하기 위한 메소드- 접근자(Accessor)
- 데이터 필드 반환 (Getter)
- 변경자(Mutator)
- 데이터 필드 설정 (Setter)
- 접근자(Accessor)
- 잘못 된 값으로 객체가 만들어지는 것을 막기 위한 접근자와 변경자
원뿔 클래스 개선
멤버 __r과 __h에 대한 접근자와 변경자 정의
- 클래스에 잘못 된 접근 차단하기
- 접근자와 변경자 통한
private
데이터 필드 접근- 만들어진 객체들이 정상 범위 내에서 동작하도록 해야함
- 데이터 필드 값 접근 막아야 함
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
class pCone: def __init__(self, radius = 20, height = 30): # 초기자 지정 if radius > 0 and height > 0: self.__r = radius # private 선언 -> 객체 외부에서는 접근이 불가능한 반지름과 높이 값 self.__h = height def get_vol(self): vol = 1 / 3 * 3.14 * self.__r ** 2 * self.__h #데이터 필드의 r과 h라는 것을 알려주기 위해 꼭 self.를 앞에 표시해주어야 함 return vol def get_surf(self): suf = 3.14 * self.__r ** 2 + 3.14 * self.__r * self.__h return suf def get_radius(self): # 접근자 통한 데이터 필드 반환 return self.__r def set_radius(self, radius): # 변경자 통한 데이터 필드 설정 if radius > 0:# 음수 값이 입력되지 않도록 if문으로 제어 self.__r = radius
1 2 3 4 5 6 7
perfect_cone = pCone(100, 200) perfect_cone.get_vol() # 기존에 보였던 데이터 필드 r, h가 보이지 않음 perfect_cone.r = -50 print(perfect_cone.get_surf())
BMI 클래스 활용
가상의 이름, 나이, 몸무게, 키를 사용하여 BMI 객체를 사용하는 프로그램
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
class BMI: def __init__(self, name, age, weight, height): # 초기자 지정 self.__name = name # 입력 파라미터에 들어온 값들을 데이터 필드에 넣어주는 작업 self.__age = age self.__weight = weight self.__height = height def get_BMI(self): return self.__weight / (self.__height) / 100 ** 2 def get_status(self): # 위에서 반환 된 BMI 값을 가지고 판정하는 부분 BMI = self.get_BMI() if BMI >= 25: return "비만" elif BMI >= 23 and BMI < 25: return "과체중" elif BMI >= 18.5 and BMI < 23: return "정상" else: return "저체중"
연습 문제
다음 중 객체 지향 패러다임의 특징이라고 할 수 없는 것은?
a. 개방화
- 객체 지향 패러다임의 특징
- 추상화
- 캡슐화
- 상속
- 객체 지향 패러다임의 특징
다음 코드의 빈 칸에 공통으로 들어가야 하는 것은?
a.
self
다음 코드의 실행 결과는?
1
"I love python".replace("o", "i").upper()
a.
"I LIVE PYTHIN"
학습 정리
- 객체와 객체 사이의 상호작용으로 프로그램을 구성하는 프로그래밍 패러다임을 객체 지향이라고 함
- 객체 지향 패러다임의 특징에는 추상화, 캡슐화, 상속, 다형성이 있음
- 클래스는 실 세계의 사물에 대한 상태(데이터)와 연산(메소드)을 표현한 단위임
- 클래스는 객체의 행동을 정의하는 메소드와 객체의 상태를 초기화하는 특수 메소드로 구성 됨
- 모든 메소드의 첫 번째 매개 변수는 self 임
- 클래스의 생성자(constructor)호출을 통해 클래스의 인스턴스인 객체가 생성 됨
- 클래스의 생성자는 클래스의 이름과 동일하며 초기자의 매개 변수를 사용함
- 객체의 데이터 필드 접근 및 메소드 호출에 객체 멤버 접근 연산자(
.
)를 사용함 - 객체의 데이터 필드의 직접 변경을 방지하기 위해 사용자의 직접적 접근을 차단하기 위해 데이터 은닉을 사용함
private
데이터 필드는 클래스 내부에서만 접근 가능하며 앞 두 밑줄(__
)로 정의함private
데이터 필드에 대해 접근하기 위한 접근자와 변경자 메소드가 정의되어야 함