뒤죽박죽 데이터분석 일기장
[Python] [4일차] Class 파트 1 본문
안녕하세요! 이번 포스트에서는 파이썬 강의 4일 차에 공부한 class에 대해서 복습하려고 합니다.
간단하게 클래스는 변수와 함수를 묶어서 코드를 작성하는 방법 합니다.
그리고 객체지향을 구현하는 문법이기도 합니다.
여기서 객체지향 이란 실제세계를 모델링하여 프로그램을 개발하는 개발 방법론입니다.
또한 협업을 용이하게 한다는 장접도 있습니다.
클래스 사용업은 저번 포스트에서 공부했던 함수 사용법과 유사합니다.
기존 함수 사용법은
: 함수선언(코드작성) > 함수호출(코드실행)
그러고 클래스 사용법은
: 클래스선언(코드작성) > 객체생성(메모리 사용) > 메서드실행(코드실행)과 같은 방식으로 진행됩니다.
여기서 메서드라는 단어는 쉽게 이렇게 생각하면 됩니다.
클래스 안에 있는 함수 | 메서드 |
클래스 바깥에 있는 함수 | 함수 |
비유하자면
클래스선언(설계도작성) > 객체생성(제품생산) > 메서드실행(기능사용)으로 생각하면 편합니다.
또 하나 알아야할 것은 식별자 컨벤션이 다르다는 것입니다.
보통 일반적인 변수나 함수는 : snake_case를 사용합니다.
→ 소문자, 언더바 사용
하지만 클래스는 : PascalCase, UpperCamelCase를 사용합니다.
→ 단어마다 앞에 대문자 사용
클래스(Class)
자 이제 기본적인 클래스 하나를 만들어 예제를 들어보겠습니다.
1. 클래스 선언 : 코드작성
# 계산기 설계 : Calculator : number1, nubmer2, plus(), minus()
class Calculator:
number1, number2 = 1,2
def plus(self):
return self.number1 + self.number2
def minus(self):
return self.number1 - self.number2
여기서 self 란 객체 자기 자신을 나타내는 변수입니다.
즉, self.number1 이라고 하면 class 안에 저장되어 있는 값의 number1입니다.
2. 객체생성 : 메모리 사용
calc1 = Calculator()
calc2 = Calculator()
3. 메서드 실행 : 코드 실행
: 클래스를 저장한 객체에서 클래스에 원하는 함수를 넣어 출력합니다.
calc1.plus(), calc1.minus()
결과:
만약, 우리가 특정 클래스에 대해서 잘 알지 못한다면 dir 이라는 함수를 통해서 어떤 메서드들이 저장되어 있는지 알 수 있습니다.
# dir() : 객체에 들어있는 변수를 풀력해 주는 함수
dir()
# lowdash 데이터들만 List comprehension으로 삭제하기
[var for var in dir(calc1) if var[0] != '_']
결과:
List comprehension을 사용해 calc1 (클래스를 저장한 객체)에 dir 함수를 적용시켜 저장된 메서드를 출력할 수 있습니다.
클래스 안에 변수 수정
기존에 list 나 dictionary에서 값을 수정하려면
a = [1,2,3,4,5]
a[0] = 100
이런식으로 특정값을 지정해 update 해 값을 수정할 수 있었습니다.
이와 마찬가지로 클래스 안에 있는 변수를 변경할 수 있습니다.
# 기존의 리스트나 딕션너리 업데이트할 때처럼 업데이트를 해주면된다
# 클래스를 설계할 때 변수를 기능이라고 생각하면 편하다.
calc1.number1 = 20
calc1.number1, calc1.number2, calc2.number1, calc2.number2
결과:
위와 같이 값이 변경되는것을 확인할 수 있습니다.
클래스 예제 은행 입출금 클래스 만들기
이번에는 클래스 안에 입금, 출금할 수 있는 메서드를 넣어보겠습니다.
1. 클래스 선언 : 은행계좌 : Account : balance, insert(), withdraw()
class Account:
balance = 0
def insert(self, money):
self.balance += money
def withdraw(self,money):
if self.balance >= money:
self.balance -= money
else:
print(f"잔액이 {money - balance} 부족합니다")
2. 객체 생성
# 객체생성
account_1 = Account()
account_2 = Account()
account_1.balance, account_2.balance
3. 매서드실행
# 메서드실행
account_1.insert(10000)
account_1.balance, account_2.balance
결과:
클래스는 만드는 3가지 단계로 정리해서 은행 입출금 클래스를 생성할 수 있었습니다.
클래스 예제 은행 입출금 클래스 만들기 - 생성자 매써드 : __init__( ) 사용
생성자 매서드: __init__ 은 주로 객체를 생성(3단계 중 2단계)에서 실행되는 메서드입니다.
변수의 초기값을 설정할 때 주로 사용합니다.
불량 객체(매서드 사용 x) 만들어질 확률을 줄여준다는 장점이 있습니다.
위의 예제를 그대로 가져와서 기존에 클래스 안에 있는 변수는 없애주고 생성자 메서드를 넣어 초기값을 설정해 보겠습니다.
1. 클래스 생성
class Account:
def __init__ (self, balance=2000): #추가된 생성자 매서드
self.balance = balance #아무것도 입력하지 않으면 balance에 2000이 할당된다.
def insert(self, amount):
self.balance += amount
def withdraw(self, amount):
if self.balance >= amount:
self.balance -= amount
else:
print(f'잔액이 {amount - balance}원 부족합니다.')
2. 객체 생성 : 메모리 사용 / 변수의 초기값을 입력함
# 객체 생성 : 메모리 사용 / 변수의 초기값을 입력함
account = Account()
이렇게 객체를 생성하게 되면 클래스 안에 있는 balance 기본값 2000원이 저장되게 됩니다.
account = Account(10000)
하지만 이렇게 입력하게 된다면 초기값이 2000원이 아닌 10000원으로 저장되게 됩니다.
Balance가 기본값 2000원으로 저장되어있다고 가정하고 메서드를 실행시켜 보겠습니다.
3. 매써드 실행 : 코드 실행 : 기능사용 : 불량품 생산
account.insert(3000)
결과:
이렇게 5000원에 입력하게 됩니다.
정리하자면 생성자 메서드를 이용하면 손쉽게 초기값을 설정할 수 있습니다.
클래스의 데이터 타입
이번엔 클래스의 데이터 타입에 대해서 설명하려고 합니다.
우리가 아까 만든 account라는 은행 입출금 클래스의 데이터 타입은 뭘까요?
# account의 데이터 타입은 Account
# account 객체가 만들어진 클래스는 Account이다
# 데이터 타입 == 클래스 > 클래스는 데이터 타입이다.
# Account 클래스는 우리가 만듦 > 사용자 정의
# 클래스는 사용자 정의 데이터 타입이다.
type(account)
결과:
Account의 데이터 타입은 Account입니다.
하지만 아래의 코드 같은 경우 데이터 타입은 list입니다.
# data의 데이터 타입은 list
# data 객체가 만들어진 클래스는 list
# list 클래스는 우리가 만들지 X
data = [1, 2, 3]
type(data)
Account와 list의 차이점은 Account는 우리가 손수 만든 사용자 정의 데이터 타입이고 list는 우리가 만들지 않는 기본으로 저장되어 있는 데이터 타입입니다.
하지만 각각의 다른 데이터 타입에 따라서 사용할 수 있는 변수와 메서드가 모두 다릅니다.
코딩을 잘하기는 위해서는 이런 변수와 메서드를 모두 외워야 할까요?

답은 아닙니다. 우린 손쉽게 데이터 타입에 내재되어 있는 변수와 메서드를 출력해 확인할 수 있습니다.
아까 복습한 dir 함수를 통해서 확인할 수 있습니다.
data1, data2 = 'python', [1,2,3] # 문자열, 리스트
print(type(data1), type(data2))
print([var for var in dir(data1) if var[0] != '_'])
print([var for var in dir(data2) if var[0] != '_'])
결과:
이렇게 저장되어 있는 메서드와 변수를 각각 데이터 타입에 따라서 출력할 수 있습니다.
참고로 List comprehension에 dir 함수를 이용해 조건문과 반복문을 통해 출력했습니다.
저번 포스트에서 이야기했던 docstring을 응용해서 이 메서드 중에서 원하는 메서드를 help 함수에 대입해서 더 자세히 알 수 있을 것입니다.
스페셜 메서드
몇 개의 추가적인 스페셜 메서드에 대해서 공부해 보겠습니다.
이번에 공부해볼 매세 드는
__add__() : + 연산자 정의
__str__() : print() 함수 실행 정의
이 두 가지 메서드입니다.
보통 우리가 연산을 하려고 하면
n1 = 1, n2 = 3
n1 + n2
이렇게 기본적인 코드를 통해 연산 결과를 출력합니다.
하지만 __add__( ) 메서드를 통해서 연산 결과를 출력할 수 있습니다.
위의 스페셜 메서드들을 통해 덧셈연산을 하지만 뺄셈연산이 수행되는 객체를 생성을 만들어 보겠습니다.
1. 코드 선언
# 덧셈연산을 하지만 뺄셈연산이 수행되는 객체를 생성
class Number:
def __init__(self, data):
self.data = data
def __add__(self, obj):
return self.data - obj.data
def __str__(self): #For call to str(). Prints readable form
return str(self.data)
def __repr__(self): #For call to repr(). Prints object's information
return str(self.data)
2. 객체 선언
# 객체 생성
num1 = Number(10)
num2 = Number(3)
num1.data, num2.data
3. 코드 실행
num1 + num2
결과 :
솔직히 이 부분은 너무 어려워서 내가 이해한 대로 한 번 설명해 보겠다.
아까 말했듯이 클래스도 데이터 타입이다. 그리고 파이썬에서는 데이터 타입마다 연산되는 것이 각각 다르다.
Number이라는 클래스에서는 덧셈을 기능하는 special method __add__에 오브젝트가 뺄셈이 된다는 구문을 작성하였다.
그러고 num1과 num2에 해당되는 숫자를 기입하고 +로 연산하였다.
두 객체는 Number이라는 클래스에 속하는 데이터 타입의 연산이다. 그리고 우리는 Number 클래스에 덧셈의 연산이 뺄셈을 기능한다고 스페셜 메서드를 이용해 정리하였다.
그래서 결괏값이 뺄셈으로 출력되는 것이다. Why? 같은 데이터 타입이기 때문에.
상속
이번에는 상속이라는 개념에 대해서 이해해 보려고 하는데요.
상속이란?
: 다른 클래스의 변수(메서드 포함)를 가져와서 사용하는 방법입니다.
그리고 만약 클래스끼리 중복되는 메서드가 있다면 코드줄을 줄이기 위해서 중복값을 없애줄 수도 있습니다.
예시를 들어보겠습니다.
class iPhone1:
def call(self):
print('calling!')
class iPhone2:
def call(self):
print('calling!')
def send_msg(self):
print('send_msg!')
class iPhone3:
def call(self):
print('calling!')
def send_msg(self):
print('send_msg!')
def internet(self):
print('internet!')
여기에 iPhone1, iPhone2, iPhone3이라는 3가지 클래스가 있습니다. 하지만 1,2,3 순으로 서로 겹치는 부분이 있습니다. 우린 상속을 사용해서 중복되는 값이 겹칠 때 코드를 간략화합니다.
상속을 사용할 경우
1. 코드 선언
# 상속 사용 - 중복되는 값이 겹칠 때 코드를 간략하기 위해 상속을 사용
class iPhone1:
def call(self):
print('calling!')
class iPhone2(iPhone1): #iPhone1 함수가 iPhone2 함수에 상속
def send_msg(self):
print('send_msg!')
class iPhone3(iPhone2): #iPhone2 함수가 iPhone3 함수에 상속
def internet(self):
print('internet!')
2. 객체 선언
iphone1 = iPhone1()
iphone2 = iPhone2()
iphone3 = iPhone3()
3. 클래스 안에 있는 메서드를 보여주는 함수 만들어서 체크
def show_vars(obj) :
return [var for var in dir(obj) if var[0] != "_"]
show_vars(iphone1), show_vars(iphone2), show_vars(iphone3)
결과:
다중상속
다중상속은, 여러 클래스를 한 번에 상속시키는 것입니다.
예제를 통해 알아보겠습니다.
class Celebrity:
def outlook(self):
print("handsome")
class Rich:
def money(self):
print("rich!")
class Car:
def drive(self):
print("Bugatti!")
3가지 클래스를 생성하겠습니다. 이 클래스들을 가지고 새로운 클래스에 상속해 보겠습니다. (물론, 여러 개도 가능합니다)
1. 코드 생성
class Ronaldo(Celebrity, Rich, Car):
def skill(self):
print("football")
2. 객체 선언
ronaldo = Ronaldo()
3. 코드실행
ronaldo.drive()
결과:
이런 식으로 여러 개의 클래스를 한 번에 상속시킬 수 있습니다.
데코레이터
데코레이터란?
: 함수에서 중복되는 코드를 빼서 데코레이터 함수로 만들어 코드를 작성하는 방법입니다.
원래 있던 함수에 새로운 기능을 추가한 함수로 변경할 때 주로 사용합니다.
예시
def func1():
print('code1')
print('code2')
print('code3')
def func2():
print('code1')
print('code4')
print('code3')
위의 코드를 보면 코드 1과 코드 3이 출력될 때 중복되는 것을 확인할 수 있습니다.
데코레이션 코드를 사용해서 위의 코드를 간략화해보겠습니다.
먼저, deco code부터 생성해 보겠습니다.
def deco(func):
def wrapper(*args, **kwargs):
print('code1')
func()
print('code3')
return wrapper
위의 코드를 보면 처음으로 wrapper가 쓰였습니다.
여기서 wrapper 함수란?
: 실제 함수(original function)를 감싼 함수(wrapper function)로, 실제 함수 호출 시 특별한 동작을 하도록 기능을 덧붙인 함수를 말합니다.
* 출처: 점프투 파이썬
Wrapper 함수는 아래와 같이 사용할 수 있습니다.
# deco 함수의 파라미터 func에 func1이 들어감
# func1 함수는 deco 함수의 return 함수인 wrapper 함수로 변경
@deco
def func1():
print('code2')
@deco
def func2():
print('code4')
func1()
func2()
결과:
처음 실행했던 코드와 똑같은 결괏값이 나오는 것을 확인할 수 있습니다.
데코레이터 - 예시
이번엔 데코레이터의 다양한 활용 방법에 대해서 알아보겠습니다.
함수가 실행되는 시간을 측정할 수 있는 데코 함수를 생성해 보겠습니다.
# timer 데코레이터 함수 생성
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time() # 현재시간 저장
result = func(*args, **kwargs)
end = time.time() # 현재시간 저장
print(f'running time : {end - start} sec')
return result
return wrapper
@timer
def plus(n1, n2):
return n1 + n2
@timer
def minus(n1, n2):
return n1 - n2
그러고 함수 앞에 생성한 데코 함수에 @을 붙여서 위치시키면 아래의 결괏값을 확인할 수 있습니다.
plus(2,3)
결과:
두 번째, 예제로는 비밀번호를 입력해야 함수를 실행시킬 수 있는 데코레이터 함수를 생성해 보겠습니다.
def admin(func):
def wrapper(*args, **kwargs):
pw = input("비밀번호를 입력해주세요: ")
if pw == 'ronaldo':
result = func(*args, **kwargs)
else :
result = "잘못된 비밀번호 입니다."
return result
return wrapper
우선, 데코 함수를 먼저 생성했습니다. 비밀번호 ronaldo를 입력해야 함수를 실행시킬 수 있게 설계했습니다.
그럼 비밀번호로 실행시킬 간단한 함수에 데코 함수를 적용시켜 보겠습니다.
@admin
def plus(n1, n2):
return n1 + n2
결과:
그럼 만약 비밀번호를 틀렸을 때는 어떤 식으로 생성될까요?
이번 포스트에서는 클래스에 대해서 알아보았습니다. 강사님이 말씀해 주시길 클래스 개념을 알고 있어야 다른 사람이 만들어 놓은 모델을 볼 때도 이해할 수 있다고 합니다. 그만큼 어렵고도 중요한 클래스 개념을 복습해 봤습니다. 혹시 틀린 개념이 있다면 댓글로 지적해주시면 감사하겠습니다.
'Python' 카테고리의 다른 글
[Python] [5일차] 입출력, 파일 저장 및 출력 (0) | 2023.01.07 |
---|---|
[Python] [5일차] Class 파트 2 (2) | 2023.01.06 |
[Python] [강의 3일차] 함수 (0) | 2023.01.04 |
[Python] [2일차] 조건문, 반복문 (2) | 2023.01.03 |
[Python] [2일차] 데이터 Skill 비교, 연산자 (0) | 2023.01.03 |