Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

뒤죽박죽 데이터분석 일기장

[Python] [5일차] Class 파트 2 본문

Python

[Python] [5일차] Class 파트 2

시우마이 2023. 1. 6. 17:19

안녕하세요. 이번 포스트는 저번 포스트에 이어서 클래스에 대해 더 알아보려고 합니다. 

 

우선, 프로퍼티에 대해서 복습하려고 합니다. 

 

getter 와 setter 이 두 가지 메서드가 있는데요. 

getter 값을 가져오는 메서드 
setter 값을 저장하는 메서드 

 

파이썬에서는 @property 라는 데코레이터를 사용해 구현할 수 있습니다. 

 

  • @property
  • @메서드이름.setter

이제 예시를 들어서 확인해 보겠습니다. 

 

비밀번호를 입력하고 수정하는 class를 getter와 setter 메서드로 표현해 보겠습니다. 

 

class Person:

    def __init__(self, pw):
        self.hidden_pw = pw

	#getter
    @property
    def pw(self):				
        print('getter')
        return self.hidden_pw

	#setter
    @pw.setter
    def pw(self, pw):			
        print('setter')			
        self.hidden_pw = pw
        
person = Person('abcd') # 비밀번호 대입/ 객체선언

 

setter 메서드로 수정하기:

person.pw = 'qwer'

 

이제 setter 메서드로 새로운 패스워드가 시스템에 입력되었는지 getter 메서드를 통해서 알아보겠습니다. 

 

 

person.pw

결과:

보시면 getter 메서드로 출력한 결과 성공적으로 수정되었습니다. 

 

하지만, 비밀번호가 저렇게 쉽게 변경되면 문제가 생기겠죠? 

 

그래서 우리는 위 함수를 응용해서 이미 입력되어 있는 비밀번호를 입력해야 비밀번호를 변경할 수 있는 클래스를 만들어 보겠습니다. 

 

class Person:

    def __init__(self, pw):
        self.hidden_pw = pw
    
    @property
    def pw(self):
        print('getter')
        return self.hidden_pw[:2] + '****'

    @pw.setter
    def pw(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.hidden_pw:
            self.hidden_pw = new_pw
        else:
            print('wrong password!')
  

person = Person('abcd') #초기 비밀번호 값/ 객체 선언

위의 클래스의 코드를 완성하고 객체 선언을 해서 초기 비밀번호를 'abcd'로 설정했습니다.

 

그럼, 아까 했던 거와 마찬가지로 setter 메서드를 이용해서 값을 변경해 보겠습니다.

 

person.pw = 'qwer'

결과: 

 

이런 식으로 잘못된 초기 비밀번호를 입력하면 비밀번호 값을 수정할 수 없습니다. 이렇게 비밀번호의 보안성을 유지할 수 있습니다. 

 

또한 getter 메서드로 비밀번호를 출력하려고 하면 

person.pw

결과:

 

이런식으로 마스킹되서 출력됩니다. 

 

하지만 사실 비밀번호를 출력할 수 있습니다. 

 

 

바로 진짜 패스워드가 저장되어 있는 식별자의 이름을 알면 파악할 수 있습니다. 

 

person.hidden_pw='qqqq'

이렇게 식별자의 이름을 알면 바로 바꿀 수 있습니다. 

 

mangling

 

따라서 이런 오류까지 방지하기 위해서 mangling 이라는 개념 적용시켜보겠다. 

 

mangling 이란 변수에 직접적으로 접근하는 것을 막는 방법이다. 

 

사용하는 방법은 변수명 앞에 __, 즉 로우대시 두개를 붙인다. 

 

이렇게 되면 위의 구문처럼 직접적으로 바꾸는 것은 불가능해지지만 원래 함수대로 비밀번호 값을 제대로 입력한다면 값을 변경할 수 있다. 

 

class Person:

    def __init__(self, pw):
        self.__hidden_pw = pw

    def getter(self):
        print('getter')
        return self.__hidden_pw

    def setter(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.__hidden_pw:
            self.__hidden_pw = new_pw
        else:
            print('wrong password!')

    pw = property(getter, setter)

 

메서드의 종류


이번엔 클래스 안에 있는 메서드의 종류에 대해서 복습해 보려고 한다. 

 

메서드는 총 3가지로 분류되어 있는데 : 인스턴스 메서드, 클래스 메서드, 스태틱 메서드로 나뉘어져 있다. 

 

1. 인스턴스 메서드 

: 파라미터 self : 객체를 이용해서 매서드 호출 

 

2. 클래스 메서드

: 파라미터 cls : 클래스를 이용하여 메서드 호출 : 객체로 생성된 초기 변수값을 모두 수정 

 

3. 스태틱 매서드 

: 파라미터 x : 객체를 선언하지 않고 매서드 호출 

 

이번에는 이자율을 계산하는 클래스 안에 위의 3가지 메서드를 포함해 비교하면 설명해보겠습니다. 

 

class Account: 
    interest = 1.01 #이자율 1프로 

    def __init__(self, asset=10000):
        self.asset = asset 

    def deposit(self, amount):
        self.asset += amount 

    def withdraw(self, amount):
        if self.asset >= amount:
            self.asset -= amount
        else: 
            print('total asset', self.asset)

    def add_interest(self): 
        self.asset = int(self.asset * self.interest)
        print('total asset', self.asset)

# 이자율을 변경해주는 인스턴스 매서드 
    def change_interest(self, interest):
        if interest <= 1.10:
            self.interest = interest 
        else:
            print("이자율을 10% 미만으로 설정해주세요.")

    @classmethod
    def cls_change_interest(cls, interest):
         if interest <= 1.10:
            cls.interest = interest 
         else:
            print("이자율을 10% 미만으로 설정해주세요.")

    @staticmethod
    def interest_grade(interest):
        if interest > 1.05: 
            print('high interest')
        elif interest > 1.02:
            print('middle interest')
        else:
            print('low interest')

 

객체 선언: 

account1 = Account(10000)
account2 = Account(20000)
account3 = Account(30000)

#출력
account1.asset, account2.asset, account3.asset,\
account1.interest, account2.interest, account3.interest

결과: 

 

객체선언 후 출력해 본 결과 아래와 같이 입력된 잔고와 현재 이자율을 확인할 수 있다. 

 

1. 인스턴스 메서드를 사용해서 이자율을 변경해보겠다. 

account1.change_interest(1.09)
account1.asset, account2.asset, account3.asset,\
account1.interest, account2.interest, account3.interest

결과: 

설명:

인스턴스 메서드를 이용해 account1의 이자율을 변경하였다. 

 

2. 클래스 매서드 사용 

Account.cls_change_interest(1.04)
account1.asset, account2.asset, account3.asset,\
account1.interest, account2.interest, account3.interest

결과: 

설명:

모든 이자율 기초값이 1.04로 변경되었다. 하지만 account1의 이자율은 변경되지 않았다. 그 이유는 인스턴스 매서드로 직접 변경된 값은 클래스 매서드를 사용해도 주소값이 다르기 때문에 변하지 않는다. 

 

3. 스태틱 매서드 사용

Account.interest_grade(account1.interest)
Account.interest_grade(account2.interest)

결과: 

설명:

클래스 매서드와 스태틱 매서드의 차이는 클래스 매서드는 클래스의 변수에 접근이 가능하지만 반대로 스태틱 메서드는 그렇지 않다. 

 

TIP: 아까 배운 mangling 개념도 똑같이 적용시킬 수 있다. 

 

class Account:

    interest = 1.01 # 이자율 1%

    def __init__(self, asset=10000):
        self.asset = asset
    #함수 mangling
    def __show_asset(self):
        print('total asset', self.asset)

    def deposit(self, amount):
        self.asset += amount
    
    def withdraw(self, amount):
        if self.asset >= amount:
            self.asset -= amount
        else:
            self.__show_asset()

    def add_interest(self):
        self.asset = int(self.asset * self.interest)
        self.__show_asset()

    def change_interest(self, interest):
        if interest < 1.10:
            self.interest = interest
        else:
            print('이자율을 10% 미만으로 설정해주세요.')

    @classmethod
    def cls_change_interest(cls, interest):
        if interest < 1.10:
            cls.interest = interest
        else:
            print('이자율을 10% 미만으로 설정해주세요.')
    
    @staticmethod
    def interest_grade(interest):
        if interest > 1.05:
            print('high interest')
        elif interest > 1.02:
            print('middle interest')
        else:
            print('low interest')

    @classmethod
    def cls_change_interest(cls, interest):
         if interest <= 1.10:
            cls.interest = interest 
         else:
            print("이자율을 10% 미만으로 설정해주세요.")

    @staticmethod
    def interest_grade(interest):
        if interest > 1.05: 
            print('high interest')
        elif interest > 1.02:
            print('middle interest')
        else:
            print('low interest')

 

 

클래스 설계: is a,  has a 개념


is a 

: A is a B

: 상속을 이용하여 클래스 설계

 

has a

: A has a B 

: 객체를 객체에 넣어서 클래스 설계 

 

첫번째, is a 개념을 이용한 클래스 설계 예제

# is a 
class Info: 
    def __init__(self, name, email): 
        self.name = name 
        self.email = email
        
class Person(Info):
    def show(self):
        print(self.name,self.email)

 

처음에 Info 클래스 생성 후 밑에 Person 클래스의 상속시킨다. 

person = Person('peter', 'peter@gmail.com')
person.name, person.email

결과: 

 

두번째, has a 개념을 이용한 클래스 설계 예제

 

처음에 두 개의 클래스를 생성해줍니다. 

 

# has a
class Name:
    def __init__(self, name):
        self.name_str = name

class Email:
    def __init__(self, email):
        self.email_str = email

설명: 이름과 이메일을 할당하는 두 개의 함수입니다. 

 

class Person:
    def __init__(self, name_obj, email_obj):
        self.name = name_obj
        self.email = email_obj
    def show(self):
        print(self.name.name_str, self.email.email_str)

그러고 Person이라는 하나의 클래스를 생성해서 출력되는 프로그램을 생성해 줍니다. 

 

그 이후에 우선 처음에 만들었던 2개의 클래스의 객체선언을 해줍니다. 

 

name_obj = Name('peter')
email_obj = Email('peter@gmail.com')

 

그러고 이전에 선언했던 Person class에 대입해줍니다. 

 

person = Person(name_obj, email_obj)
person.show()

결과: