본문 바로가기
AI SCHOOL/TIL

[DAY 9] 클래스, 객체, 메소드

2023. 1. 5.

객체 지향 : 실제 세계를 모델링하여 프로그램을 개발하는 개발 방법론

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의 출력 결과가 잘 출력되었다.

반응형

댓글