본문 바로가기
python

[python]파이썬 - 클래스class2

by skysline 2023. 1. 24.
반응형

상속

  • 구현된 클래스의 기능(메소드)을 그대로 가져다가 사용하거나 아니면 그기능을 수정하거나 아니면 기능을 추가하거나 할때 사용하는 개념
  • 부모클래스의 속성(인스턴스변수와 메소드)들을 자식클래스가 그대로 물려받는 개념
  • 확장 개념, 부모클래스와 자식클래스가 합쳐지는 개념
 
  • 부모 클래스 먼저 정의해보자.
 
 
 
class PlayerCharacter:
    def __init__(self,hp=100,exp=0):
        self.hp = hp
        self.exp = exp

    def attack(self):
        print("공격하기")
        self.exp = self.exp + 2

    def defend(self):
        print("방어하기")
        self.exp = self.exp + 1
 
 
  • 부모클래스를 상속 받는 자식 클래스 정의하자
 
 
 
class Wizard(PlayerCharacter): # 상속 받기
    def __init__(self,mp):
        self.mp = mp
        # super(Wizard,self).__init__() # 2.x 버전대 사용방식
        super().__init__() # 부모클래스의 생성자를 실행하겠다.

    def magic_skill(self):
        print("마법 공격하기")
        self.mp = self.mp - 2
 
 
 
 
player = Wizard(10)
player.attack()
 
공격하기
 
 
 
player.hp
 
100
 
 
 
  1
player.exp
 
2
 
 
 
player.attack()
player.exp
 
공격하기
4
 
  • 상속을 하면 정말 합쳐지는게 맞는지 주소값 확인해봅시다.
 
 
 
class PlayerCharacter:
    def __init__(self,hp=100,exp=0):
        print(f"부모의 주소값: {id(self)}")
        self.hp = hp
        self.exp = exp

    def attack(self):
        print("공격하기")
        self.exp = self.exp + 2

    def defend(self):
        print("방어하기")
        self.exp = self.exp + 1

class Wizard(PlayerCharacter): # 상속 받기
    def __init__(self,mp):
        print(f"자식의 주소값: {id(self)}")
        self.mp = mp
        # super(Wizard,self).__init__() # 2.x 버전대 사용방식
        super().__init__() # 부모클래스의 생성자를 실행하겠다.

    def magic_skill(self):
        print("마법 공격하기")
        self.mp = self.mp - 2
 
 
 
 
Wizard(30)
 
자식의 주소값: 140111519357136
부모의 주소값: 140111519357136
<__main__.Wizard at 0x7f6e415718d0>
 

오버라이딩(Override)

  • 부모로부터 받는 메소드를 수정하고 싶을때 자식클래스에서 재정의 한다.
 
 
 
class PlayerCharacter:
    def __init__(self,hp=100,exp=0):
        self.hp = hp
        self.exp = exp

    def attack(self):
        print("공격하기")
        self.exp = self.exp + 2

    def defend(self):
        print("방어하기")
        self.exp = self.exp + 1

class Wizard(PlayerCharacter): # 상속 받기
    def __init__(self,mp):
        self.mp = mp
        # super(Wizard,self).__init__() # 2.x 버전대 사용방식
        super().__init__() # 부모클래스의 생성자를 실행하겠다.

    def magic_skill(self):
        print("마법 공격하기")
        self.mp = self.mp - 2

    # 메소드 오버라이딩
    def defend(self):
        print("마법사가 방어하기")
        self.exp = self.exp + 3
 
 
 
 
player = Wizard(20)
print(player.exp)
player.defend()
player.exp
 
0
마법사가 방어하기
3
 
- Calculator 클래스를 상속받아 add, sub, mul ,div 메소드를 오버라이딩하여 구현하기
- add, sub, mul ,div 메소드에 num 파라미터의 값이 정수가 아닐 경우 
"입력값이 정수가 아닙니다. 입력값을 0으로 변경합니다." 
출력과 함께 num 파라미터값을 0 값으로 변경한다.
- mul, div 메소드에 경우 0값이 아규먼트로 들어왔을 경우 연산은 하지 않는다.
 
 
 
class Calculator:
    def __init__(self,num=0):
        self.num = num

    def add(self,num): # 한개의 정수를 입력 받아 self.num 더하기, 반환값 X
        pass
    def sub(self,num): # 한개의 정수를 입력 받아 self.num 빼기, 반환값 X
        pass
    def mul(self,num): # 한개의 정수를 입력 받아 self.num 곱하기, 반환값 X
        pass
    def div(self,num): # 한개의 정수를 입력 받아 self.num 나누기, 반환값 X
        pass

    def result(self):
        return self.num 
    def reset(self):
        self.num = 0
 
 
 
 
class MyCalculator(Calculator):
    
    def __init__(self,num):
        super().__init__(num) # 부모생성자에 아규먼트 넣어주기

    def add(self,num):
        self.num = self.num + self.check_num(num) # 정수가 아닐경우 0 이 반환됨
    def sum(self,num):
        self.num = self.num + self.check_num(num) # 정수가 아닐경우 0 이 반환됨
    def mul(self,num):
        if self.check_num(num): # 0 이 아닐경우는 True!
            self.num = self.num * num
    def div(self,num):
        if self.check_num(num): # 0 이 아닐경우는 True!
            self.num = self.num / num
    def check_num(self,num):
        if type(num) is not int: # num 파라미터가 int가 아닐경우 True!
            print("입력값이 정수가 아닙니다. 입력값을 0으로 변경합니다.")
            num = 0
        return num
 
 
 
 
mc = MyCalculator(3)
mc.add(3)
mc.result()
mc.reset()
mc.result()
 
0
 
  • 표준화 스케일링
    • 데이터의 평균을 0 분산을 1인 분포로 변환환다.
    • 그냥 편차를 표준편차로 나눈거다.
      xμσ
 
Scaler 클래스를 상속받아 StandardScaler 클래스를 구현하시오
Scaler 클래스 fit_transform 와 transform 를 오버라이딩하시오
fit_transform 에 경우는 인자로 받은 데이터의 평균값과 표준편차를 인스턴스변수에 저장하고
인자로 받은 데이터를 표준화하여 스케일링을 적용하고 반환하시오
transform 에 경우는 저장된 인스턴스변수를 이용하여 입력받은 데이터를 표준화하여 스케일링을 적용하고 반환하시오
 
 
 
class Scaler:
    def fit_transform(self,data):
        pass
    def transform(self,data):
        pass
 
 
 
 
class StrandardScaler(Scaler):

    # 메소드 오버라이딩
    def fit_transform(self,data):
        self.avg_ = self.get_avg(data)
        self.std_ = self.get_std(data)
        return [ (x - self.avg_) / self.std_ for x in data]
        # return self.transform(data)
    
    # 메소드 오버라이딩
    def transform(self,data):
        return [ (x - self.avg_) / self.std_ for x in data]

    def get_avg(self,data):
        return sum(data) / len(data)

    def get_std(self,data):
        avg = self.get_avg(data)
        diff_list = [ (avg - x)**2 for x in data]
        var = sum(diff_list) / len(data)
        return var ** 0.5
 
 
 
data = [3000,3500,4000,9000,8000,12000]
ss = StrandardScaler()
ss.fit_transform(data)
 
[-1.0787144762791367,
 -0.9281961772634433,
 -0.7776778782477497,
 0.7275051119091854,
 0.4264685138777984,
 1.6306149060033466]
 
 
 
tmp = ss.transform(data)
 
 
 
 
tmp
 
[-1.0787144762791367,
 -0.9281961772634433,
 -0.7776778782477497,
 0.7275051119091854,
 0.4264685138777984,
 1.6306149060033466]
 
  • 데이터의 평균이 0 인지 확인해보자.
ss.get_avg(tmp)
 
7.401486830834377e-17
 
  • 분산과 표준편차가 1인지 확인해보자.
 
ss.get_std(tmp)
 
1.0
 
- Scaler 클래스를 상속받아 MinMaxScaler 클래스를 구현하시오
- Scaler 클래스 fit, fit_transform , transform, inverse_transform 를 오버라이딩하시오
- fit 은 데이터의 최소값과 사이즈값(최대값- 최소값)을 인스턴스변수에 저장하는 기능을 구현하시오
- fit_transform 은 데이터의 최소값과 사이즈값(최대값- 최소값)을 인스턴스변수에 저장하는 기능과 함께 
입력받은 데이터를 minmax 스케일링을 적용하고 반환하시오
- transform 은 저장된 인스턴스변수를 이용하여 입력받은 데이터를 minmax 스케일링을 적용하고 반환하시오
- inverse_transform 은 minmax 스케일이 적용된 데이터를 입력받아 원래의 수치로 변경하는 기능을 구현하시오.
 

 

xMin(X)Max(X)Min(X)
  • 역변환
    x×(Max(X)Min(X))+Min(X)
 
 
class Scaler:
    def fit(self,data):
        pass
    def fit_transform(self,data):
        pass
    def transform(self,data):
        pass
    def inverse_transform(self,data):
        pass
 
 
 
 
class MinMaxScaler(Scaler):
    def fit(self,data):
        self.min_ = min(data)
        self.size_ = max(data) - self.min_
    def fit_transform(self,data):
        self.fit(data)
        return [ (x - self.min_) / self.size_ for x in data]
    def transform(self,data):
        return [ (x - self.min_) / self.size_ for x in data]
    def inverse_transform(self,data):
        return [ x * self.size_ + self.min_ for x in data ]
 
 
 
 
data = [3000,3500,4000,9000,8000,12000]
mms = MinMaxScaler()
mms.fit(data)
mms.min_ , mms.size_
 
(3000, 9000)
 
 
 
tmp = mms.transform(data)
tmp
 
[0.0,
 0.05555555555555555,
 0.1111111111111111,
 0.6666666666666666,
 0.5555555555555556,
 1.0]
 
 
 
mms.inverse_transform(tmp)
 
[3000.0, 3500.0, 4000.0, 9000.0, 8000.0, 12000.0]
 

non public(private 화)

  • private: 인스턴스 변수나 메소드를 클래스 내부에서만 사용하게 하는것
  • 바깥에서 사용이 불가능하도록 하는 설정
  • 맹글링(mangling) 기법을 이요해서 외부에서 직접적으로 인스턴스변수나 메소드에 접근하는것을 막을수 있다.
 
 
 
class PlayerCharacter:
    def __init__(self,hp=100,exp=0):
        self.hp = hp
        self.exp = exp

    def attack(self):
        print("공격하기")
        self.exp += 2

    def defend(self):
        print("방어하기")
        self.exp += 1

    def attacked(self,attack_size):
        print("공격받음")
        self.hp -= attack_size
 
 
 
 
class Wizard(PlayerCharacter):
    def __init__(self,mp):
        super().__init__() 
        self.__mp = mp # private
    
    def __magic_skill(self): # private
        print("마법 공격하기")
        self.__mp -= 2

    def magic_skill(self):
        if self.__mp > 1:
            self.__magic_skill()
        else:
            print("MP가 부족합니다.")
 
 
 
 
player = Wizard(50)
player.__magic_skill()
 
 
 
player.magic_skill()
 
마법 공격하기
 
 
 
player = Wizard(1)
player.magic_skill()
 
MP가 부족합니다.
 
 
 
player.__mp
 
 
 
player.__mp = 100
 
 

getter & setter (참고용)

  • 인스턴스 변수에 접근할때 특정 로직을 거쳐서 접근시키는 방법
  • getter & setter 정의할 인스턴스 변수는 private 화 하자.
 
 
 
class Wizard(PlayerCharacter):

    def __init__(self,mp):
        super().__init__()
        self.mp = mp
        self.hp = 0

    # getter 세팅할때는 다음의 데코레이터 정의
    @property
    def mp(self):
        print("getter 동작")
        return self.__mp
    
    # setter 세팅할때는 getter 의 메소드명.setter
    @mp.setter
    def mp(self,mp):
        print("setter 동작")
        if mp < 0:
            mp = 0
        self.__mp = mp
 
 
 
player = Wizard(5)
player.hp
 
setter 동작
0
 
 
player.mp
 
getter 동작
5
 
 
player.mp = -1
 
setter 동작
 
 
player.mp
 
getter 동작
0
 

매직 메소드(이건 중요)

  • 메소드 명이 두개의 언더바로 감싸져 있다.
  • 파이썬의 다양한 내장함수들이 클래스의 매직 메소드들을 호출하여 결과를 만들어 낸다.
 
 
 
class MyDataset:
    def __init__(self,data):
        self.data = data

    def __call__(self,a):
        print(f"{a} 함수 호출 방법처럼 객체를 함수 호출하듯이 만들어주는 메소드")

    def __str__(self): # print 함수에 이 클래스의 객체를 넣을경우 이메소드에 리턴값을 출력해준다.
        return "My dataset Class"

    def __len__(self): # len() 내장함수는 객체의 이 매직메소드를 호출한다고 생각하면 된다.
        return len(self.data)

    def __getitem__(self,idx): # 인덱싱과 슬라이싱을 가능하게 한다.
        return self.data[idx]
 
 
 
 
data = list(range(50,100))
dt = MyDataset(data)
dt
 
<__main__.MyDataset at 0x7f2582077b50>
 
 
dt(1004)
 
1004 함수 호출 방법처럼 객체를 함수 호출하듯이 만들어주는 메소드
 
 
 
print(dt)
 
My dataset Class
 
 
len(dt)
 
50
 
 
 
dt[:5]
 
[50, 51, 52, 53, 54]
 
객체 생성시 딕셔너리 데이터를 입력 받아 다음과 같은 예시로 데이터를 반환하는
클래스를 만드시오.


ex)
data = {
    "x" : [0.4,0.3,0.8,0.2,0.3,0.9,0.7], 
    "y" : [0,1,0,0,1,0,0]
}

dt = Dataset(data)
len(dt)
Output:
7

dt[0]
Output:
(0.4, 0)


class Dataset:
    def __init__(self,data):
        pass
    def __len__(self):
        pass
    def __getitem__(self,idx):
        pass
 
 
 

data = {
    "x" : [0.4,0.3,0.8,0.2,0.3,0.9,0.7], 
    "y" : [0,1,0,0,1,0,0]
}
class Dataset:
    def __init__(self,data):
        self.x = data["x"]
        self.y = data["y"]
    def __len__(self):
        return len(self.y)
    def __getitem__(self,idx):
        return self.x[idx] , self.y[idx]

dt = Dataset(data)
len(dt)
7
 
dt[0]
(0.4, 0)
 
 
dt[-3:]


([0.3, 0.9, 0.7], [1, 0, 0])
반응형

댓글