python

__(double underscore)

sklass 2021. 8. 27. 00:02

python에서 _(single underscore)가 변수 앞에 붙으면 private으로 지정하자는 네이밍 룰(naming rule)로 쓰입니다. 

하지만 __(double underscore)가 붙는 경우(ex: __variable), 네이밍 룰이라기보다는 python의 문법적인 요소로 생각해야 합니다. 바로 네임 맹글링(name mangling)을 위한 경우로, 파이썬이 해당 변수/함수의 이름을 짓이겨서 바꿔버리는 것을 의미합니다.

 

맹글링을 당한 변수/함수는 본연의 이름으로 접근할 수 없게됩니다. 아래의 예제를 살펴 보겠습니다.

class TestClass():
	def __init__(self):
    	self.name = "Joseph"
        self.__age = 20
        
test = TestClass()

print(test.name)
>> 'Joseph'

print(test.__age)
>> AttributeError: 'TestClass' object has no attribute '__age'

 

그렇다면 어떻게 __age에 접근할 수 있을까요?

 

dir 함수를 까보면 마지막에 name이 보이고 바로 첫 인덱스에 _TestClass__age라는 이름이 보입니다.

print(dir(test))
>> ['_TestClass__age', '__class__', '__delattr__', '__dict__', 
	'__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
	'__getattribute__', '__gt__', '__hash__', '__init__', 
	'__init_subclass__', '__le__', '__lt__', '__module__', 
	'__ne__', '__new__', '__reduce__', '__reduce_ex__', 
	'__repr__', '__setattr__', '__sizeof__', '__str__', 
	'__subclasshook__', '__weakref__', 'name']
    
print(test._TestClass__age)
>> 20

 

네임 맹글링(name mangling)을 언제 사용하나요?

파이썬에서 맹글링을 사용하는 상황은 크게 2가지로 볼 수 있습니다.

  1. 클래스의 속성값을 외부에서 접근하기 힘들게 할 때
  2. 하위 클래스가 상위 클래스의 속성을 오버라이딩 하는 것을 막을 때

 

1. 클래스의 속성값을 외부에서 접근하기 힘들게 할 때

이는 위에서 다룬 코드들에 대한 내용으로, TestClass의 age라는 속성을 숨기고 싶을 때 사용합니다. 이는 private과는 조금 다른 개념인데, 이유는 위의 네임 스페이스를 확인하면 알 수 있듯이 __age가 _Test__age로 저장되면서, 아예 접근 불가능하게 만드는 것은 아니고, 접근할 수 있는 변수의 이름이 달라지는 것이라고 이해하면 되겠습니다.

 

2. 하위 클래스가 상위 클래스의 속성을 오버라이딩 하는 것을 막을 때

클래스가 확장되면서 크기가 커지면 발생할 수 있는 문제인 속성 이름간의 충돌을 막고자 할 때, 특히 오버라이딩을 막고자 할 때 맹글링을 적용시킬 수 있습니다.

class TestClass:
    def __init__(self):
        self.name = "Joseph"
        self.age = 30


class TestClass2(TestClass):
    def __init__(self):
        super().__init__()
        self.name = "Chris"
        self.age = 23


test = TestClass2()

print(test.name, man.age)
>> 'Chris, 23'

해당 코드는 아무런 조치를 취하지 않았기 때문에 어떤 제약도 없이 하위 클래스에서 상위 클래스의 속성들을 오버라이딩 할 수 있게 됩니다.

 

class TestClass:
    def __init__(self):
        self.name = "Joseph"
        self.__age = 30


class TestClass2(TestClass):
    def __init__(self):
        super().__init__()
        self.name = "Chris"
        self.__age = 23


test = TestClass2()
print(test.name, test.__age)
>> AttributeError: 'TestClass2' object has no attribute '__age'

하지만 위와 같이 오버라이딩을 막고 싶은 속성(name)에 맹글링을 적용시키면 AttributeError가 발생합니다. 이름이 이제 _TestClass__age와 _TestClass2__age로 변경되었기 때문에, __age 속성을 애초에 가지고 있지 않은 것으로 취급합니다.