본문 바로가기
Python/Python FAQ

Python 파이썬의 'private' 메소드들이 실제로는 왜 비공개가 아닌가요?, Why are Python's 'private' methods not actually private?

by 베타코드 2023. 6. 30.
반응형

질문


파이썬은 클래스 내에서 이름 앞에 이중 밑줄을 사용하여 '비공개' 메서드와 변수를 생성할 수 있습니다. 예를 들어 이렇게 사용할 수 있습니다: __myPrivateMethod(). 그렇다면, 이것을 어떻게 설명해야 할까요?

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass 인스턴스에는 '__myPrivateMethod' 속성이 없습니다.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

무슨 일이 일어나는 걸까요?!

이해하기 어려웠던 분들을 위해 간단히 설명하겠습니다.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

public 메서드와 private 메서드를 가진 클래스를 생성하고 인스턴스를 만듭니다.

다음으로, public 메서드를 호출합니다.

>>> obj.myPublicMethod()
public method

다음으로, private 메서드를 호출해봅니다.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass 인스턴스에는 '__myPrivateMethod' 속성이 없습니다.

여기서는 모든 것이 정상적으로 보입니다. 호출할 수 없습니다. 실제로 '비공개'입니다. 그러나 사실은 그렇지 않습니다. 객체에 대해 dir()을 실행하면 모든 '비공개' 메서드에 대해 파이썬이 자동으로 생성하는 새로운 마법 메서드가 나타납니다.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

이 새로운 메서드의 이름은 항상 밑줄로 시작하고, 그 뒤에 클래스 이름, 그리고 메서드 이름이 옵니다.

>>> obj._MyClass__myPrivateMethod()
this is private!!

캡슐화에 대해 말하려 했던 건 말이죠?

어쨌든, 파이썬은 캡슐화를 지원하지 않는다고 들었는데, 그렇다면 왜 시도해볼까요? 무슨 이유일까요?


답변


The name scrambling is used to ensure that subclasses don't accidentally override the private methods and attributes of their superclasses. It's not designed to prevent deliberate access from outside.

For example:

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...     
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

Of course, it breaks down if two different classes have the same name.

반응형

댓글