public
, private
속성?노출모듈 패턴에 대해 조사하던 중, 문득 파이썬으로는 이 패턴이 어떻게 구현되어 있을지 궁금해졌다. 내 주 언어가 파이썬이기 때문. 아래와 같은 글을 찾게 되었다.
"public" or "private" attribute in Python ? What is the best way?
class Foo:
self._attr = 0
@property
def attr(self):
return self._attr
@attr.setter
def attr(self, value):
self._attr = value
@attr.deleter
def attr(self):
del self._attr
📝 Note
파이썬 3에서는private
속성(엄밀히 말하면protected
속성)을 사용하려면 언더스코어를 2개 사용해야 한다. 12년 전 올라온 글이라 파이썬 2 문법을 사용하고 있다.
질문자 Sandro Munda는 이런 방식이 KISS(Keep it simple, stupid!의 약자) 원칙에 위배는거 아닌가 하는 의문을 가졌다고 한다. 특정한 getter
/setter
/deleter
메서드가 필요하지 않다면 그냥 public
속성으로 선언/초기화하는게 더 낫지 않은가 하는 의문이다. 다만 OOP 방법론의 Encapsulation 원칙이 이렇게 하라고 하기 때문에 뭐가 더 나은지에 대해 질문했다.
여러 답변이 달렸고 그 중 흥미로운 댓글을 발견했다. 이 댓글을 살펴보기 전에 어떤 답변이었는지 먼저 보도록 하자.
요지는 이러하다. 파이썬은 UAP(Uniform Access Principle)을 지키려고 한다. 보통 아래와 같이 접근한다:
public
변수를 사용해라. (foo.attr(x)
대신 공개속성(attr
) 사용 후 foo.attr = x
)@property
데코레이터를 사용해라.^1 그러면 foo.attr += 1
이 실행될 때 내부적으로 foo.attr(foo.attr()+1)
가 실행된다. 인자가 전달되지 않은 attr
메서드는 getter
, 인자가 전달된 attr
메서드는 setter
이다. 첫 번째 접근이 더 읽기 쉽다. 두 번째 방법은 접근을 컨트롤하기 더 용이하다.
하지만 파이썬에서 언더스코어를 사용해 private
속성을 만드는 것은 어디까지나 컨벤션이라고 한다. 아무리 직접 접근하지 못하게 하더라도, 접근할 수 있는 방법은 있다.
예를 들어, 다음과 같은 코드가 있을 때,^2
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
def update(self, iterable):
for item in iterable:
self.items_list.append(item)
__update = update # private copy of original update() method
class MappingSubclass(Mapping):
def update(self, keys, values):
# provides new signature for update()
# but does not break __init__()
for item in zip(keys, values):
self.items_list.append(item)
m = MappingSubclass([1, 2, 3])
# Mapping 클래스의 __update 속성에 저장된 update 함수
m.__getattribute__('_Mapping__update')
m._Mapping__update
# m은 여전히 자기 자신의 update 메서드를 가지고 있다.
m.update
위와 같이 비공개 속성을 호출할 수 있다( name mangling
이라고 한다).
그런데 이 글에 다음과 같은 댓글이 달렸다:
How do I argue/discuss with a Java dev that this does not make the programming language "worse" or that it doesnt just "miss a feature"?
by raitisd, Dec 15, 2016 at 15:18^3
"어떻게 이게 Java보다 못나거나 기능이 없는게 아니라는걸 논증할 수 있는가?" Brian Clapper는 다음과 같이 답한다:
I always point out that, unlike Ruby, Python, Scala, and C# (to name just a few), Java is actually worse, because it demonstrably fails to adhere to the Uniform Access Principle. As a result, the coder has to type (or the IDE has to generate) getters and setters defensively, most of which don't add any real value—and all of which mean there's more useless code to wade through when maintaining the class.
by Brian Clapper, Feb 4, 2017 at 20:27^4
"Java가 못난거야. UAP를 따르는데 실패했거든. "
이어서 다음 댓글을 보자
@BrianClapper "fails to adhere to the Uniform Access Principle" - coming from the JVM world, this is what we're thought to avoid as it makes the code less "secure". I mean, let's imagine we have some mutable properties internal to the class and it's business logic that you want to hide from others... not sure I'd want that public. I'm interested in finding out why you think it is important to have this principle adhered to when building a language. Totally open-minded, give me some refs
by milosmns, Jul 26, 2019 at 12:51^5
"어 그렇긴 한데, 이거 코드를 좀 더 안전하게 만들려는 예외야"
@milosmns If someone has access to the code base, you can't hide the business logic from them. See this and this for why UAP might be better, apart from the answer itself. by Harshvardhan, May 28, 2022 at 14:45^6
"뭔소리임? 어차피 코드베이스에 접근할 수 있으면, 숨길 수 있는 건 없어."
결론은 위 두 링크 찾아보고 나서 내리자.