객체 지향 : 실제 세계를 모델링하여 프로그램을 개발하는 개발 방법론
Class
- 변수와 함수를 묶어서 코드를 작성하는 방법
- 객체 지향을 구현하는 문법
- 사용법 : 클래스 선언(코드 작성) -> 객체 생성(메모리 사용) -> 메소드 실행(코드 실행)
- 실제 세계에 비유 : 설계도 작성 -> 제품 생산 -> 기능 사용
- 통상 클래스는 pascal case(upper camel case), 변수와 함수는 snake case로 작성
관련용어 : class, self, special method, 상속, super, getter-setter, mangling 등
코드를 통해 알아보자.
1. 클래스 선언 : 코드 작성 - 계산기 클래스
# 계산기 설계 : number1, number2를 이용해서 덧셈, 뺄셈 기능 구현
class Calculator:
number1, number2 = 1, 2
def plus(self):
return self.number1 + self.number2
def minus(self):
return self.number1 - self.number2
2. 객체 생성 : 메모리 사용
# Calculator 객체 2개 생성
calc1 = Calculator()
calc2 = Calculator()
객체를 생성한 후 dir() 함수를 통해 객체에 들어 있는 변수, 함수 목록을 출력
# dir() : 객체에 들어 있는 변수 목록을 출력
lst = [var for var in dir(calc2) if var[0] != '_']
print(lst)
# 실행 결과
['minus', 'number1', 'number2', 'plus']
각 객체에 변수 값 확인
print(calc1.number1, calc1.number2, calc2.number1, calc2.number2)
# 실행 결과
1 2 1 2
3. 메소드 실행 : 코드 실행
print(calc1.plus(), calc2.minus())
# 실행 결과
3 -1
각 객체의 plus() 메소드와 minus() 메소드 실행 결과 1+2, 1-2 값이 잘 출력됨을 알 수 있다.
이번에는 calc1의 변수 number1을 수정한 후 다시 메소드를 실행해 보자.
# 객체의 변수 수정
calc1.number1 = 20
print(calc1.number1, calc1.number2, calc2.number1, calc2.number2)
print(calc1.plus(), calc2.plus())
# 실행 결과
20 2 1 2
22 3
변수 값이 수정된 것을 확인하고 다시 실행한 결과 20+2와 1+2 값이 출력되었다.
self : 객체 자신을 의미
- calc1.plus()에서 self == calc1 이므로 self.number1 + self.number2는 calc1.number1 + calc1.number2를 의미
금액 초기값이 10000원인 계좌 클래스를 생성
special method __init__()과 default parameter를 활용했다.
계좌 생성할 때 괄호 안을 비우면 10000원이 default이며, 값을 넣으면 그 값이 초기값으로 설정된다.
입금, 출금 결과 계좌 잔액을 확인할 수 있다.
코드를 직접 수정하며 금액을 바꾸어 보고 실습할 수 있다.
special method __add__()
먼저 코드를 보면
d1, d2, d3, d4 = 1, 2, '3', '4'
print(d1.__add__(d2)) # int 클래스의 __add__() 메소드
print(d3.__add__(d4)) # str 클래스의 __add__() 메소드
# 실행 결과
3
34
두 경우 모두 __add__() 메소드를 사용했지만 다른 연산을 하게 된다.
이처럼 같은 이름의 메소드를 사용하더라도 데이터 타입에 따라서 수행되는 연산이 다를 수 있다.
__add__() 메소드를 사용하지만 뺄셈 연산이 수행되는 객체를 생성해 보자
# __add__() 메소드를 사용하지만 뺄셈 연산이 수행되는 객체 생성
class Number:
def __init__(self, data):
self.data = data
def __add__(self, number):
return self.data - number
num1 = Number(10)
num2 = Number(3)
print(num1 + 5)
print(num2 + 5)
# 실행 결과
5
-2
num1 + 5가 15, num2 + 5가 8의 결과가 아닌 뺄셈의 결과를 확인할 수 있다.
상속 : 다른 클래스의 변수(메소드)를 가져와서 사용하는 방법
업그레이드되는 3가지 버전의 Phone을 구현해 보자
Phone1 기능 1개 : call
Phone2 기능 2개 : call, send_msg
Phone3 기능 3개 : call, send_msg, internet
class Phone1:
def call(self):
print('calling!')
class Phone2:
def call(self):
print('calling!')
def send_msg(self):
print('send_msg!')
class Phone3:
def call(self):
print('calling!')
def send_msg(self):
print('send_msg!')
def internet(self):
print('internet!')
중복되는 코드들이 눈에 보인다. 이럴 경우 유용하게 사용되는 것이 상속이다.
# 상속을 사용
class Phone1:
def call(self):
print('calling!')
class Phone2(Phone1): # Phone1 상속
def send_msg(self):
print('send_msg!')
class Phone3(Phone2): # Phone2 상속
def call(self): # overide
print('video calling!')
def internet(self):
print('internet!')
#객체 생성
phone1 = Phone1()
phone2 = Phone2()
phone3 = Phone3()
phone1.call()
phone2.call()
phone2.send_msg()
phone3.call()
phone3.internet()
# 실행 결과
calling!
calling!
send_msg!
video calling!
internet!
상속받은 클래스의 기능을 물려받는 개념이다. Phone3의 경우 call 메소드를 다시 작성하여 다른 동작을 하도록 바꿨다.
이를 override라고 한다.
다중 상속 : 여러 클래스를 상속받는 것 - 파이썬의 특징
파이썬 클래스는 동시에 여러 클래스를 상속받을 수 있다.
먼저 Human (걷기), Korean (김치 먹기), Indian(카레 먹기) 클래스를 선언한다.
class Human:
def walk(self):
print('walking!')
class Korean:
def eat(self):
print('eat kimchi!')
class Indian:
def eat(self):
print('eat curry!')
이후 코딩을 하는 한국인 Jin과 영어를 하는 인도인 Anchel 클래스를 선언한다.
# 코딩을 하는 한국인 Jin과 영어를 하는 인도인 Anchel 클래스 선언
# Human -> Korean -> Jin 순서로 상속
class Jin(Korean, Human): # 상속 순서도 중요
def skill(self):
print('coding')
# Human -> Indian -> Anchel
class Anchel(Indian, Human):
def skill(self):
print('speak english!')
Jin, Anchel 객체를 생성한 후 메소드를 실행해 보자.
# Jin, Anchel 객체 생성
jin = Jin()
anchel = Anchel()
jin.walk()
anchel.walk()
jin.eat()
anchel.eat()
jin.skill()
anchel.skill()
# 실행 결과
walking!
walking!
eat kimchi!
eat curry!
coding
speak english!
한국인과 인도인을 잘 구현하였다.
데코레이터(decorator) : 함수에서 중복되는 코드를 빼서 데코레이터 함수로 만든다 - 파이썬의 특징
- 원래 있던 함수에 새로운 기능을 추가한 함수로 변경할 때 주로 사용
코드를 보고 어느 부분이 중복되는지 확인, 데코레이터 사용 전후를 비교해 보자
# 데코레이터 사용 전
def func1():
print('code1')
print('code2')
print('code3')
def func2():
print('code1')
print('code4')
print('code3')
# 데코레이터 사용 후
# deco 함수의 파라미터 func에 각각 func1, func2가 들어간다
# func1, func2 함수는 각각 deco 함수의 return 함수인 wrapper 함수로 변경
def deco(func):
def wrapper(*args, **kwargs):
print('code1')
func()
print('code3')
return wrapper
@deco
def func1():
print('code2')
@deco
def func2():
print('code4')
@deco(@데코레이터 이름)를 함수 선언 바로 위 라인에 사용한다.
함수 실행 결과 확인
func1()
func2()
# 실행 결과
code1
code2
code3
code1
code4
code3
중복된 code1, code3 부분 사이에 func1, func2의 출력 결과가 잘 출력되었다.
'AI SCHOOL > TIL' 카테고리의 다른 글
[DAY 11] pandas 기초 - DataFrame, Series, Indexing 등 (2) | 2023.01.10 |
---|---|
[DAY 10] getter, setter, name mangling (0) | 2023.01.06 |
[DAY 8] parameter와 argument, lambda, list comprehension (0) | 2023.01.05 |
[DAY 7] 데이터 핸들링 스킬, 파이썬 연산자와 함수 (0) | 2023.01.05 |
[DAY 6] 코랩, 리스트와 튜플, 깊은 복사 (0) | 2023.01.05 |
댓글