본문 바로가기
AI SCHOOL/TIL

[DAY 10] getter, setter, name mangling

2023. 1. 6.

getter, setter : 객체의 내부 변수에 접근할 때 특정 메소드를 거쳐서 접근할 수 있도록 하는 방법

이름과 패스워드를 갖는 유저 객체를 생성해보자.

class User:
    def __init__(self, name, pw):
        self.name = name
        self.pw = pw

user = User('peter', 'abcd123') # 유저 객체를 생성

이름이 peter이며 패스워드를 abcd123로 사용하는 유저 객체 user를 생성했다.

유저의 패스워드를 출력 시도한다면?

print(user.pw)

# 실행 결과
abcd123

패스워드는 쉽게 공개되지 않아야 하는데 그대로 노출되었다.

문제점을 해결하기 위해 패스워드 변수에 대해 제한 사항을 설정한다.
먼저 패스워드를 출력하는 경우 앞 2글자만 보여지고 나머지는 별표로 처리한다.
그리고 패스워드 변경할 경우 현재 패스워드를 입력해야 하며 틀릴 경우 'wrong password'를 출력한다.

getter, setter 설정방법은 decorator를 이용하는 방법과 property 함수를 이용하는 방법이 있다.
두 방식 코드는 기능상 차이가 없다.
1. decorator 이용 방법

# decorator 이용 방법
class User:
    def __init__(self, name, pw):
        self.name = name
        self.hidden_pw = pw
    
    @property
    def pw(self):
        print('getter')
        return self.hidden_pw[:2] + '*' * len(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
            print('password changed')
        else:
            print('wrong password')

해당 형태에서 패스워드에 접근하여 값을 얻는 메소드와 값을 변경하는 메소드의 이름은 일치시켜야 하며
decorator는 @property, @메소드이름.setter 형태로 사용한다.

2. property 함수 이용 방법

# property 함수 이용 방법
class User:
    def __init__(self, name, pw):
        self.name = name
        self.hidden_pw = pw
        
    def getter(self):
        print('getter')
        return self.hidden_pw[:2] + '*' * len(self.hidden_pw[2:])
        
    def setter(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.hidden_pw:
            self.hidden_pw = new_pw
            print('password changed')
        else:
            print('wrong password')
            
    pw = property(getter, setter)  # property 함수 사용

 

위와 같이 2가지 방법을 통해 코드를 바꿔 제한사항을 설정한 후, 전과 같이 패스워드에 접근해 보자.

user = User('peter', 'abcd123')
user.pw = 'qwer456'  # 값을 저장할 때는 setter 함수를 거침

# 실행 결과
setter
insert password : abcd123
password changed

유저 객체를 생성하고 패스워드를 qwer456으로 변경하는 과정에서 현재 패스워드 abcd123를 입력해야 변경이 가능하게 되었다.

print(user.pw)

# 실행 결과
getter
qw*****

변경된 패스워드 qwer456 중 qw만 마스킹되지 않고 출력된 결과를 볼 수 있다.

하지만 두 방식 모두 문제점이 있다.

user.hidden_pw = 'kkkk99'  # 문제점 : 직접 접근해서 변경
print(person.hidden_pw)  # 문제점 : 직접 접근해서 확인

# 실행 결과
kkkk99

User 객체의 hidden_pw 변수에 직접 접근하여 패스워드를 변경하고 확인할 수 있었다.


name mangling
이를 해결하기 위해 맹글링을 사용한다.
변수를 non public 하게 만들어 주어 숨기는 방식(은닉)하는 방식이다.
변수 앞에 __(double underscore)를 붙여주는 형태로 사용한다.

위에서 소개한 property 함수를 이용한 getter, setter에 name mangling을 적용해 보자.

# property 함수 이용 + name mangling 이용 방법
# hidden_pw 변수 앞에 __ 추가
class User:
    def __init__(self, name, pw):
        self.name = name
        self.__hidden_pw = pw
    def getter(self):
        print('getter')
        return self.__hidden_pw[:2] + '*' * len(self.__hidden_pw[2:])
    def setter(self, new_pw):
        print('setter')
        input_pw = input('insert password : ')
        if input_pw == self.__hidden_pw:
            self.__hidden_pw = new_pw
            print('password changed')
        else:
            print('wrong password')
    pw = property(getter, setter)


name mangling까지 적용한 클래스를 활용해서 객체를 만들고 패스워드에 접근해 보자.

user = User('jonadan', 'erty677')
print(user.pw)

# 실행 결과
getter
er*****

패스워드 erty677인 현 상태

-> __hidden_pw 변수에 직접 uqwe88로 변경 시도 후 확인

person.__hidden_pw = 'uqwe88'  # 에러는 나지 않음
print(user.pw)

# 실행 결과 - 패스워드가 변경되지 않았다
getter
er*****


다시 setter를 통해 변경 시도

user.pw = 'uqwe88'

# 실행 결과
setter
insert password : erty677
password changed

 

print(user.pw)

# 실행 결과
getter
uq****

__hidden_pw 변수 직접 접근은 불가하지만 setter를 통해서는 잘 변경된 것을 확인할 수 있다.

그러나...

print(user._User__hidden_pw)

# 실행 결과
uqwe88

사실 내부적으로 _클래스명이 name mangling 된 변수 앞에 붙는다.
클래스를 엄격하게 통제하지 않는 파이썬의 특성상 맹글링을 사용해도 직접 접근을 완전히 막을 수는 없다.

반응형

댓글