기록하는삶
[파이썬/python] 클래스(Class), 클래스 상속 본문
파이썬은 객체지향(OOP _ Object Oriented Programming) 언어이다.
객체 = 속성(상태, 특징)과 행위(행동, 동작, 기능)로 구성된 대상
> 속성: '변수'로 구현
> 행위: '함수'로 구현
즉, 객체란 특정 목적을 달성하기 위한 변수와 함수들의 묶음이다.
ex) 아래 링크의 유튜브 강의에서는 class를 자기소개서에 빗대어 표현하였다.
https://www.youtube.com/watch?v=uIcK7-YU8uA
파이썬에서 객체를 생성하는 방법인 Class에 대해 예시를 통해 살펴보자. 아래는 자전거의 정보(이름, wheel_size, color, model_code)를 통해 자전거를 등록하고, 등록된 자전거의 행위(move, turn, stop, auto_cruise) 등을 정의한 Class이다.
Class를 정의할 때 보통 snake_case가 아닌 CamelCase로 그 이름을 부여한다.
- snake_case: 띄어쓰기 대신 _를 사용하는 표기법. 변수, 함수명에 사용
- CamelCase: 띄어쓰기 대신 대문자를 사용하는 표기법. Class명에 사용
class Bicycle():
num = 0 # 클래스변수 정의, 클래스 내 모든 인스턴스에 적용되는 공통된 변수
def __init__(self, wheel_size, color, model_code):
self.wheel_size = wheel_size
self.color = color
self.model_code = model_code
Bicycle.num = Bicycle.num + 1
def __str__(self):
return "자전거의 wheel_size는 %d, 색은 %s, 코드는 %d입니다." % \
(self.wheel_size, self.color, self.model_code)
def __add__(self, other):
return "Class 객체 간의 더하기를 정의합니다. 두 자전거의 코드 합은 %d입니다." % \
(self.model_code + other.model_code)
def move(self, speed):
print("{1}자전거: 시속 {0:03d}킬로미터 전진".format(speed, self.color), end='\t')
self.speed = speed
def turn(self, direction):
print("{0}자전거: {1}회전".format(self.color, direction))
def stop(self):
print("자전거({0},{1}): 정지".format(self.wheel_size, self.color))
def auto_cruise(self):
self.move(self.speed)
print("자율주행시작")
@staticmethod
def check_type(model_code):
if model_code == 10:
print("이 자전거는 일반자전거입니다.")
elif model_code == 20:
print("이 자전거는 전기자전거입니다.")
elif model_code == 30:
print("이 자전거는 하이브리드자전거입니다.")
@classmethod
def count_bi(cls):
print("등록된 총 자전거 수는 {0}대 입니다.".format(cls.num))
1) __init__(self, 변수1, 변수2, 변수3, ...)
Class가 선언과 동시에 실행되는, Class 선언을 위해 필수적으로 필요한 함수이다. self는 선언할 때의 변수명을 의미하고 변수 1,2,3은 선언할 때 입력해주어야 하는 변수들, 즉 일종의 형식을 말한다. 위의 예시에서 Bicycle이라 선언되기 위해서는 변수명(self)와 3개의 변수가 필요하다.
my_bicycle = Bicycle(30, 'white', 10)
your_bicycle = Bicycle(33, 'blue', 20)
super_bicycle = Bicycle(35, 'red', 30)
다음과 같이 정의하면 총 3개의 자전거가 각 my_bicycle, your_bicycle, super_bicycle이란 이름으로 등록된다. 이때 각각을 인스턴스(instance)라 부른다.
2) __str__(self)
양 쪽에 두 개의 언더바(__)로 둘러쌓인 함수는 예약된 함수다. 그 중 하나인 __str__는 클래스 선언 후 해당 클래스를 print 했을 때의 결과를 저장해놓는 함수다.
따로 __str__() 함수를 지정하지 않는다면, 아래의 결과를 반환한다.
3) __add__(self, other)
마찬가지로 예약 함수 중 하나로, 선언된 두 객체의 합을 정의할 수 있다.
4) 클래스 변수(class variable)와 인스턴스 변수(instance variable)
instance가 선언되기 이전에 정의된 변수 'num = 0'의 경우 모든 하위 객체가 공통으로 가지는 클래스 변수(class variable)이다. 반면 __init__ 함수 아래에 정의된 self.xxx의 변수들의 경우 instance가 선언됨과 동시에 정의되므로 인스턴스 변수(instance variable)이고, 해당 instance에서만 사용된다. 정의된 변수들은 self.xxx로 접근이 가능하다.
5) __init__ 제외 하위 함수들(move, turn, stop, auto_cruise)
모두 인스턴스명(self).함수명(변수)의 형태로 활용될 수 있다. 사용 예시는 아래와 같다.
6) @staticmethod _ 정적 메서드
클래스와 관련있어 내부에 정의하지만, 클래스에 정의되는 인스턴스들과 무관하게 독립적으로 동작하는 함수들은 @staticmethod를 선언하고 그 아래에 정의한다. 예시에서 자전거 종류를 code에 따라 구분하는 행위(함수)는 정의되는 하위 인스턴스들과는 무관하다.
7) @classmethod _ 클래스 메서드
위의 변수의 구분에서 'num = 0'은 하위 인스턴스들과 무관한 클래스 변수였다. 이러한 클래스 변수를 활용하는 함수들은 @classmethod를 선언하고 그 아래에 정의한다.
또 다른 예시를 살펴보자.
class Robot():
def __init__(self, name, pos):
self.name = name
self.pos = pos
def move(self, step):
self.pos = self.pos + step
print("{0} position : {1}".format(self.name, self.pos))
robot1 = Robot('R1',0)
robot2 = Robot('R2', 10)
robot1.move(10)
로봇 클래스를 정의하고, 이동을 하는 간단한 코드다. 이렇게 이미 선언되어 있는 클래스가 가진 변수 혹은 행위를 그대로 이용하되, 추가하고 싶은 경우에 클래스 상속을 이용할 수 있다.
class AIrobot(Robot):
def __init__(self, name, pos, state, bootnum):
#Robot.__init__(self, name, pos)와 같은 기능, 부모에게서만 정의한 것을 사용하려면 필요
super().__init__(name, pos)
self.state = state
self.bootnum = bootnum
def reboot(self):
self.state = "rebooting"
print("{0}, {1} 위치에서 재부팅을 시작합니다.".format(self.name, self.pos))
self.bootnum = self.bootnum + 1
def booted(self):
self.state = "on"
print("{0}, {1} 위치에서 부팅을 완료했습니다.".format(self.name, self.pos))
def intro(self):
print("{0}는 AI로봇이며, 현재 {1}에 위치해있습니다. 지금까지 {2}번의 재부팅을 했습니다.".format(self.name, self.pos, self.bootnum))
robot100 = AIrobot("R100", 12, 'on', 0)
robot101 = AIrobot("현아", 20, 'on', 0)
두 가지만 기억하면 된다.
1) Class 선언시, '클래스이름(상속받고자 하는 클래스):'
2) '__init__'의 아래에 'super().__init__(name, pos)' 을 통해 상속받고자 하는 클래스가 가졌던 __init__의 규칙 불러오기
나머지는 동일하다. 아래는 사용 예시.
[참고]
class SupervisedTrainer(object):
"""
The SupervisedTrainer class helps in setting up training framework in a supervised setting.
Args:
optimizer (kospeech.optim.__init__.Optimizer): optimizer for training
criterion (torch.nn.Module): loss function
trainset_list (list): list of training datset
validset (kospeech.data.data_loader.SpectrogramDataset): validation dataset
num_workers (int): number of using cpu cores
device (torch.device): device - 'cuda' or 'cpu'
print_every (int): number of timesteps to print result after
save_result_every (int): number of timesteps to save result after
checkpoint_every (int): number of timesteps to checkpoint after
"""
train_dict = {'loss': [], 'cer': []}
valid_dict = {'loss': [], 'cer': []}
train_step_result = {'loss': [], 'cer': []}
TRAIN_RESULT_PATH = "train_result.csv"
VALID_RESULT_PATH = "eval_result.csv"
TRAIN_STEP_RESULT_PATH = "train_step_result.csv"
def __init__(
self,
optimizer: Optimizer, # optimizer for training
criterion: nn.Module, # loss function
trainset_list: list, # list of training dataset
validset: SpectrogramDataset, # validation dataset
num_workers: int, # number of threads
device: torch.device, # device - cuda or cpu
print_every: int, # number of timesteps to save result after
save_result_every: int, # nimber of timesteps to save result after
checkpoint_every: int, # number of timesteps to checkpoint after
teacher_forcing_step: float = 0.2, # step of teacher forcing ratio decrease per epoch.
min_teacher_forcing_ratio: float = 0.8, # minimum value of teacher forcing ratio
architecture: str = 'las', # model to train - las, transformer
vocab: Vocabulary = None, # vocabulary object
joint_ctc_attention: bool = False, # flag indication whether joint CTC-Attention or not
) -> None:
self.num_workers = num_workers
self.optimizer = optimizer
self.criterion = criterion
self.trainset_list = trainset_list
self.validset = validset
self.print_every = print_every
self.save_result_every = save_result_every
self.checkpoint_every = checkpoint_every
self.device = device
self.teacher_forcing_step = teacher_forcing_step
self.min_teacher_forcing_ratio = min_teacher_forcing_ratio
self.metric = CharacterErrorRate(vocab)
self.architecture = architecture.lower()
self.vocab = vocab
self.joint_ctc_attention = joint_ctc_attention
if self.joint_ctc_attention:
self.log_format = "step: {:4d}/{:4d}, loss: {:.6f}, ctc_loss: {:.6f}, ce_loss: {:.6f}, " \
"cer: {:.2f}, elapsed: {:.2f}s {:.2f}m {:.2f}h, lr: {:.6f}"
# 현재 학습 중인게 아래의 결과를 찍는다.
else:
self.log_format = "step: {:4d}/{:4d}, loss: {:.6f}, " \
"cer: {:.2f}, elapsed: {:.2f}s {:.2f}m {:.2f}h, lr: {:.6f}"
if self.architecture in ('rnnt', 'conformer'):
self.rnnt_log_format = "step: {:4d}/{:4d}, loss: {:.6f}, " \
"elapsed: {:.2f}s {:.2f}m {:.2f}h, lr: {:.6f}"
위의 예시처럼 __init__()을 정의할 때 파라미터들의 type과 default를 지정할 수 있다.
또한 __init__() 뒤의 -> None이라는 표현은, __init__() 함수가 아무 것도 반환하지 않는 함수임을 표현하는 주석이다.
외에 __init__()도 함수의 일종이므로, if문을 통해 조건에 따라 다른 실행을 하도록 설정할 수 있다.
'AI > 파이썬(Python)' 카테고리의 다른 글
[파이썬/python] EDA 기본(datetime type 변경, 중복값 제거, Null값 확인, unique 확인, 날짜정보 type변경, 히트맵) (0) | 2021.09.22 |
---|---|
[파이썬/python] 데이터 전처리(원핫인코딩_One-hot Encoding, 정규화, 표준화) (0) | 2021.09.22 |
[파이썬/python] 정규표현식을 이용해 괄호와 괄호 안의 내용 삭제하기 (2) | 2021.09.13 |
[파이썬/Python] 자연어처리 _ TfidfVectorizer (0) | 2021.08.09 |
[파이썬/Python] 자연어처리 _ Bow, CountVectorizer (0) | 2021.08.07 |