Post

(python) @property, getter setter, private 필드

프로퍼티 지정

  • protected로 만들거면 \_, private으로 만들거면 \_\_
  • 프로퍼티는 일반 변수와 같이 명명하는게 통일성 있다. 메서드지만 외부에서는 변수처럼 보여야 하니까.
  • property() 사용하는 방법도 있으나 decorator 사용하는 방법이 나아보인다.
lock 변수를 사용할 때 좋은 듯
1
2
3
4
5
6
7
8
9
10
11
12
@property
def running\_flag(self):
with self.\_\_running\_flag\_lock:
flag = self.\_\_running\_flag
return flag


@running\_flag.setter
def running\_flag(self, value):
with self.\_\_running\_flag\_lock:
self.\_\_running\_flag = value

  • getter만 정의하는 것도 가능하나 setter만 정의하는 것은 불가하다.
  • setter의 @running\_flag. 데커레이터에서 없는 변수라고 에러가 발생하기 때문.
  • 그래서 get/set 항상 같이 정의해주는게 좋을 듯 하고, 안쓰는건 raise AttributeError: unreadable attribute 처리 해주면 되겠다.
  • .__setattr__() hook을 사용한 방법도 있긴 한데 가독성 측면에서 좋지 않은 듯.
  • https://stackoverflow.com/questions/17576009/python-class-property-use-setter-but-evade-getter

private 네임 맹글링

backing field의 이름은 외부에서는 보이지 않게 하고, 프로퍼티를 사용해서만 접근하도록 해야 하므로 \_\_var 처럼 앞에 __를 붙여서 명명해준다. 이렇게 하면 name mangling해주기 때문에 바로 접근하면 없는걸로 나온다.

사실 python에서는 접근제한자라는 개념이 없기는 하지만, 프로퍼티를 쓰는건 커스텀 접근자를 정의하겠다는 의미도 있기 때문에,커스텀 접근자를 사용하는 경우 반드시 이를 거쳐서 사용하도록 강제 할 수 있다는데 의의가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> t = TestCls("qwer")
>>> t.name
'qwer'
>>> t.name = "asdf"
>>> t.name
'asdf'
>>> t.\_\_name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'TestCls' object has no attribute '\_\_name'
>>> t.\_TestCls\_\_name
'asdf'

getter / setter에서 저장된 데이터를 불러오기/쓰기 할 때 주의할 점

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
32
33
34
35
36
37
38

@status
.
setter

def
status
(
self
,
value
):


self
.\_status
=
value


with
open
(
"./config/status
.json"
,
'w'
)
as
f:

json.
dump
(
self
.\_status, f)

  • 이런 코드를 작성할 때 유의할 점은_status의 내부 필드가 모두 final이어야 한다는 점이다.
  • _status.name = “abc” 이런 식으로 지정해버리면 분명 _status는 변경되었는데 갱신되지 않는다. 그래서 final이 필수이고…
  • 아니면 아예 ORM 같은걸 쓰던가. 알아서 필드 변경에도 상태가 갱신되니까…
  • 아니면 아예 save를 별도 메서드로 빼던가.
This post is licensed under CC BY 4.0 by the author.