관리 메뉴

HAMA 블로그

파이썬에서 @property 에 대해 알아보자. 본문

Python

파이썬에서 @property 에 대해 알아보자.

[하마] 이승현 (wowlsh93@gmail.com) 2017. 4. 24. 20:46




@property 이야기 




private 와 public 

파이썬에서는 클래스 캡슐화에 필요한 접근지정자를 잘 안쓰는 편이다. 어떤 부분에서는 public 을 권장하는 느낌도 든다. public 이 훨씬 편하니깐~ㅎㅎ (예를들어 시작은 그냥 public 변수를 사용하게 하다가 먼가 제약이 필요할 때 쯤이면 아래 공부할 @property 등으로 처리한다 ) 제약보다는 자유도/책임감을 높히는 방향의 언어인 파이썬 답다. 

먼저 말해두는데 파이썬에서 접근지정자는 없다. 즉 아래와 같이 코딩해도 에러가 안난다는 뜻이다

class Test:

def __init__(self):
self.public_field = 5
self.__private_field = 6
self._protected_field = 7

def __private_method(self):
pass

if __name__ == '__main__':

t = Test()

t.public_field = 10
t.__private_field = 11
t._protected_field = 12

다만, __ 가 앞에 있으면 private, _ 한개짜리는 protected 혹은 둘 다 "웬만하면 직접 접근하지 마세요" 로 약속은 한다. 그냥 같이 개발하는 사람에게 정보 제공 정도이지 언어 자체에서 강제한다는게 아니다. 메소드도 마찬가지.




get , set 


아래 처럼 get,set 함수를 만들어서 처리 할 수도 있으며

class Test:

def __init__(self):
self.color = "red"

def set_color(self,clr):
self.color = clr

def get_color(self):
return self.color

if __name__ == '__main__':

t = Test()
t.set_color("blue")

print(t.get_color())

( 아 물론 저기에서도  t.set_color("blue") 대신해  t.color = "blue" 해도 된다. )


@property

@property 를 이용하여 이렇게도 가능하다. 코드를 보면 뭐 이런거구나 하고 바로 알 수 있을 것이다.

class Test:

def __init__(self):
self.__color = "red"

@property
def color(self):
return self.__color

@color.setter
def color(self,clr):
self.__color = clr

if __name__ == '__main__':

t = Test()
t.color = "blue"

print(t.color)


물론 강제적인 접근지정자가 존재하지 않으니

t = Test()
t.__color = "blue"

print(t.__color)

이렇게 해두 되지만 -.-;;


get 역할을 하는 어노테이션은 @property 이고, set역할을 하는 어노테이션은 @color.setter 이다. 


다른 예를 또 보자 



@property 의 파워~


아래와 같은 클래스가 있다고 해보자

class Celsius:
def __init__(self, temperature=0):
self.set_temperature(temperature)

def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32

def get_temperature(self):
return self._temperature

def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value

섭씨 -273 도 이하로 혹시 내려가는 값을 입력받으면 안되기 때문에, temperature 변수를 public 으로 만들지 않고, _temperature 식으로 만들었으며, get,set 을 추가하였다. 


하지만 위에 언급했다시피 파이썬에서 private 는 강제가 아니다. 따라서 


if __name__ == '__main__':

c = Celsius()
c._temperature = -300
print(c.get_temperature())

계산 같은 얘기 반복하지만, 이렇게도 물론 가능하다. 



@Property 를 사용해서는 

class Celsius:
def __init__(self):
pass
def to_fahrenheit(self):
return (self._temperature * 1.8) + 32

@property
def temperature(self):
print("Getting value")
return self._temperature

@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value

이렇게 만들 수 있는 것이고~



@property 를 사용하는 목적을 간단하게 정리해보면  



1. 변수를 변경 할 때 어떠한 제한을 두고 싶어서
2. get,set 함수를 만들지 않고 더 간단하게 접근하게 하기 위해서
3. 하위호환성에 도움이 됨. 
4. 등등 


이 있다. 


하위 호환성에 대해서는 아래에서 자세히 보도록 하자.




하위 호환성 


만약 내가 만든 클래스를 누군가가 사용한다고 치자.

처음 만든 클래스는  get,set 도 없었으며, 변수에 직접 접근해서 사용하는거 였다고 치자.


class
Celsius:
def __init__(self, temperature=0):
self.temperature = temperature

def to_fahrenheit(self):
return (self. temperature * 1.8) + 32



c = Celsius() c.temperature = 10


근데 추후에 클래스를 수정한다고 하면, 즉 get, set 을 만들어 넣고 set에는 -273이하로는 예러를 발생하도록 한다고 치자. 사용자는 전혀 그 혜택(?) 을 볼 수가 없다. 그냥 접근하면 되니깐~

하지만 

class Celsius:
def __init__(self):
pass


def to_fahrenheit(self):
return (self.temperature * 1.8) + 32

@property
def temperature(self):
print("Getting value")
return self._temperature

@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value

이렇게 수정하면 사용자는 전혀 코드를 바꾸지도 않아도, temperature 를 사용 할 때 자연스럽게 -273의 제약을 받게 된다.




부록: @property 는 무엇인가?


temperature = property(get_temperature,set_temperature)

내장 함수인 property가 있으며, 인자로 get, set함수가 들어간다. 이걸 편하게 사용하도록한게 @property이다.



class Celsius:
    def __init__(self, temperature = 0):
        self.temperature = temperature

    def to_fahrenheit(self):
        return (self.temperature * 1.8) + 32

    def get_temperature(self):
        print("Getting value")
        return self._temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value

    temperature = property(get_temperature,set_temperature)



레퍼런스:

Effective Python 

https://www.programiz.com/python-programming/property

Comments